foreach在ObservableCollection上抛出NullReferenceException

时间:2012-11-21 14:18:03

标签: c# .net foreach observablecollection nullreferenceexception

我有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);
}

我可以从日志中看到,这段代码有时会抛出带有消息的Exception “这里的东西是空的.a.Count:9,枚举器不为空”。当这种情况开始发生时,它会继续在每个页面加载时发生,直到我iisreset。

当然,innerexception是一个System.NullReferenceException,它有这个堆栈跟踪:

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

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

的行

为什么会抛出此异常?

修改

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

1 个答案:

答案 0 :(得分:0)

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

您将随机查看NullReferenceExceptionIndexOutOfRangeException等异常,这是最好的结果!在其他情况下,可以静默删除对集合的更改。

您可能需要在锁中包含对列表的访问权限,可能使用the ReaderWriterLockSlim class,或切换到线程安全的集合。对于.NET 4.0,System.Collections.Concurrent namespace有几种可能性。