views:

55

answers:

2

When enumerating a .NET collection, MSDN states that:

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 its behavior is undefined.

What exactly does "irrecoverably invalidated" mean?

Take a binary tree for instance, with references both down to left and right children, and also up to parent. In such a tree, a single reference to a single node in the tree is enough to navigate through the tree as you can easily find the next node in the tree from it.

So with that tree, suppose I remove some other node (presumably, I don't remove the node I'm currently sitting in), should I still invalidate the enumerator? Note that I'm not talking about multi-threaded operation here, just a single thread running a loop, and modifying the collection inside the loop body.

Is this "law" really that, a law, that even if the enumerator could continue, it shouldn't?

+8  A: 

Is this "law" really that, a law, that even if the enumerator could continue, it shouldn't?

Personally, I think that having your enumerator throw, even if it theoretically could continue, is a good practice.

Often, people inadvertently put code that changes a collection inside of a foreach loop. Without doing this, it might not be throwing in the specific instance the developer is currently testing, but a different runtime condition could easily make it throw.

By always throwing, you're forcing the developer to treat your code the same as the framework's collections and enumerations, which I think is a good thing, since it reduces the level of surprise when dealing with your library.

Reed Copsey
+1. I think the safety of throwing the exception in a consistent manner far outweighs the potential benefits of being able to continue enumeration over a collection that's been modified in a way that wouldn't impact the enumerator, just depending on its position.
Adam Robinson
That's my thought - the consistency (esp. with the framework) is of greater value than the marginal value of being able to do this in edge cases...
Reed Copsey
+2  A: 

The implementation of the standard collection enumerators makes it a law. When they are created, it copies a private "version" integer from the collection object. Modifying the collection increments that version. The iterator methods compare the version and when there's a mismatch it throws. No way to get around that.

However, there's one collection class that permits modifying the collection while they are enumerated: Microsoft.VisualBasic.Collection. It needed to do so to stay compatible with the VB6 Collection class. You might want to take a look at it to see how it is done. IIRC, it keeps a WeakReference on all iterators, then update the iterators when the collection is modified. This is not fool proof of course, removing an element and adding it back in can enumerate the same object twice. Nor is it cheap.

Hans Passant