关于更改的集合的ArgumentOutOfRangeException

时间:2016-06-10 11:50:40

标签: c# wpf multithreading locking

//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));
}

当我检查checkBox Filter方法抛出

  

未处理的类型&#39; System.ArgumentOutOfRangeException&#39;   发生在mscorlib.dll

     

其他信息:指数超出范围。必须是非负面的   并且小于集合的大小。

看起来我在检查收集时标记了ChechBox。但是我使用了锁定关键字,所以它应该是安全的,不是吗?

1 个答案:

答案 0 :(得分: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();
}