2016-06-10 23 views
0
//I have collection 
private static List<Sport> ChosenSports = new List<Sport>(); 

//and lock object for it 
private static object _lockSports = new object(); 

//I have checkbox that add or remove collection items 
private void CheckBoxSportZone_Checked(object sender, RoutedEventArgs e) 
{ 
    var chkZone = sender as CheckBox; 
    lock (_lockSports) 
    { 
     if (chkZone.IsChecked == true) 
      ChosenSports.Add(chkZone.DataContext as Sport); 
     else if (chkZone.IsChecked == false) 
      ChosenSports.Remove(chkZone.DataContext as Sport); 
    } 
} 

//And method that uses that collection 
private IEnumerable<Sport> FilterSports(HashSet<Sport> sports) 
{ 
    lock (_lockSports) 
     return sports. Where(x => ChosenSports.Contains(x)); 
} 

當我檢查複選框來過濾方法拋出ArgumentOutOfRangeException上改變總彙

類型「System.ArgumentOutOfRangeException」 未處理的異常出現在mscorlib.dll

其他信息:索引超出範圍。必須是非負數 且小於集合的大小。

看起來我在檢查收集時標記ChechBox。但是我使用鎖定關鍵字,所以它應該是安全的,不是嗎?

+2

只是出於好奇...它的工作原理,如果你重構,所以你不要在你的鎖中使用lambda,也就是把它變成一個塊而不是一行,然後做一個循環來建立最終的集合? –

回答

4

此代碼:

private IEnumerable<Sport> FilterSports(HashSet<Sport> sports) 
{ 
    lock (_lockSports) 
     return sports. Where(x => ChosenSports.Contains(x)); 
} 

僅鎖定LINQ表達式的實例化。實際枚舉表達式時,鎖將消失。

你或許應該引起ChosenSports收集到鎖內進行迭代(並返回枚舉的副本),通過調用.ToArray()像這樣:

private IEnumerable<Sport> FilterSports(HashSet<Sport> sports) 
{ 
    lock (_lockSports) 
     return sports.Where(x => ChosenSports.Contains(x)).ToArray(); 
} 
+2

對,這就是我在這個問題的評論中暗指的。 –

+0

@ roryap是的,我認爲這就是問題所在。這是過去咬我的東西! –

+0

謝謝,現在它像發條一樣運行 –