I have class ElementRelation { ... } and class ElementRelationCollection : System.Collections.ObjectModel.ObservableCollection<ElementRelation> { ... }
And I have this code:
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);
}
I can see from the logs that this code sometimes throws an Exception with message
“Something is null here. a.Count: 9, enumerator is not null”. When this starts happening it continues top happen on every page load until I iisreset.
The innerexception of course is a System.NullReferenceException and it has this stacktrace:
at MyNamespace.MyClass.MyMethod() in c:\path\MyClass.cs:line 74
where line 74 is the line that says foreach (ElementRelation relation in a)
Why does it throw this exception?
Edit:
The collection is sometimes updated by a background thread. I thought this could not cause worse problems than a failed iteration but it turns out the whole collection becomes corrupted.
The
ObservableCollection<T>class is not thread-safe. Modifying it from multiple threads can corrupt the internal state to such an extent that it becomes impossible to modify or enumerate the instance.You will randomly see exceptions such as
NullReferenceExceptionandIndexOutOfRangeException– and that’s the best possible result! In other cases, the changes to the collection could be silently dropped.You will either need to wrap your access to the list in a lock, possibly using the
ReaderWriterLockSlimclass, or switch to a thread-safe collection. For .NET 4.0, theSystem.Collections.Concurrentnamespace has several possibilities.