Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any C# collections where modification does not invalidate iterators?

Are there any data structures in the C# Collections library where modification of the structure does not invalidate iterators?

Consider the following:

List<int> myList = new List<int>();
myList.Add( 1 );
myList.Add( 2 );
List<int>.Enumerator myIter = myList.GetEnumerator();
myIter.MoveNext();  // myIter.Current == 1
myList.Add( 3 );
myIter.MoveNext();  // throws InvalidOperationException
like image 849
Phil Young Avatar asked May 02 '10 14:05

Phil Young


2 Answers

Yes, take a look at the System.Collections.Concurrent namespace in .NET 4.0.

Note that for some of the collections in this namespace (e.g., ConcurrentQueue<T>), this works by only exposing an enumerator on a "snapshot" of the collection in question.

From the MSDN documentation on ConcurrentQueue<T>:

The enumeration represents a moment-in-time snapshot of the contents of the queue. It does not reflect any updates to the collection after GetEnumerator was called. The enumerator is safe to use concurrently with reads from and writes to the queue.

This is not the case for all of the collections, though. ConcurrentDictionary<TKey, TValue>, for instance, gives you an enumerator that maintains updates to the underlying collection between calls to MoveNext.

From the MSDN documentation on ConcurrentDictionary<TKey, TValue>:

The enumerator returned from the dictionary is safe to use concurrently with reads and writes to the dictionary, however it does not represent a moment-in-time snapshot of the dictionary. The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called.

If you don't have 4.0, then I think the others are right and there is no such collection provided by .NET. You can always build your own, however, by doing the same thing ConcurrentQueue<T> does (iterate over a snapshot).

like image 60
Dan Tao Avatar answered Nov 06 '22 22:11

Dan Tao


According to this MSDN article on IEnumerator the invalidation behaviour you have found is required by all implementations of IEnumerable.

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException. If the collection is modified between MoveNext and Current, Current returns the element that it is set to, even if the enumerator is already invalidated.

like image 32
Anders Abel Avatar answered Nov 06 '22 20:11

Anders Abel