0

我有class ElementRelation { ... }class ElementRelationCollection : System.Collections.ObjectModel.ObservableCollection<ElementRelation> { ... }

我有这个代码:

ElementRelationCollection a = ...;
if (a == null)
    throw new Exception("a is null(???)"); // this exception is never thrown
try
{
    foreach (ElementRelation relation in a) // exception is thrown here
    { ... } // never thrown here
}
catch (NullReferenceException ex)
{
    string message = "Something is null here. a.Count: " + a.Count;
    IEnumerator<ElementRelation> enumerator = a.GetEnumerator();
    message += ", enumerator is " + (enumerator == null ? "null" : "not null");
    throw new Exception(message, ex);
}

我可以从日志中看到,此代码有时会引发异常,并显示消息“这里的东西为空。a.Count:9,枚举器不为空”。当这种情况开始发生时,它会在每次页面加载时继续发生,直到我 iisreset。

内部异常当然是 System.NullReferenceException,它有这个堆栈跟踪:

at MyNamespace.MyClass.MyMethod() in c:\path\MyClass.cs:line 74

其中第 74 行是说foreach (ElementRelation relation in a)

为什么会抛出这个异常?

编辑:

集合有时由后台线程更新。我认为这不会导致比迭代失败更严重的问题,但事实证明整个集合都已损坏。

4

1 回答 1

0

该类ObservableCollection<T>不是线程安全的。从多个线程修改它可能会破坏内部状态,以至于无法修改或枚举实例。

您会随机看到诸如NullReferenceExceptionIndexOutOfRangeException- 之类的异常,这是最好的结果!在其他情况下,可以静默删除对集合的更改。

您将需要将您对列表的访问权包装在一个锁中,可能使用class ReaderWriterLockSlim或者切换到一个线程安全的集合。对于 .NET 4.0,System.Collections.Concurrent命名空间有多种可能性。

于 2012-11-21T15:53:30.930 回答