2016-06-10 36 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

谢谢,现在它像发条一样运行 –