views:

86

answers:

4

Can I safely add nodes to LinkedList container inside foreach statement? Is there any difference if I used while loop? Or it is never allowed and can cause some problems?

foreach(var node in myList)
{
    if(condition)
        myList.AddLast(new MyNode());
}

Will it always work?

+1  A: 

While iterating over a collection with the foreach statement, you cannot modify it. Thus, adding items will result in a compiler error.

Marius Schulz
will using 'while' loop solve my problem?
MarcAndreson
You can use a `while` loop to loop over the collection. You will not receive a compiler error when doing this, but be careful not to write an infinite loop - which can happen if new `MyNode()` fulfills `condition`.
Marius Schulz
@Marius: It *won't* result in a compiler error. The code given will compile with no problem. It will throw an exception at execution time.
Jon Skeet
@Jon Skeet: Oops - I just remembered Visual Studio complain about this code and thought it would be a compiler error ... Thanks!
Marius Schulz
+3  A: 

You can't modify a collection while you're enumerating over it.

From the docs for LinkedList<T>.GetEnumerator:

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.

In practice I believe it will always throw an InvalidOperationException, despite the behaviour officially being undefined.

EDIT: You asked in a comment whether a while loop would help... a while loop using GetEnumerator/MoveNext/Current wouldn't, but this will:

LinkedListNode<MyNode> current = myList.First;
while (current != null)
{
    if (condition) // use current.Value to get the value
    {
        myList.AddLast(new MyNode());
    }
    current = current.Next;
}

As far as I'm aware, that's entirely safe and predictable. You can always ask a node for its next node. If you happen to be looking at the tail node and add another one, you'll get the new tail node when you ask for "next".

If that doesn't help, please give us more details about what you're trying to achieve.

Jon Skeet
Entirely safe is a stretch, endless loop and OOM if the new node matches the condition.
Hans Passant
+2  A: 

No, enumerator object remembers internal version of owning collection. After collection is modified - version changed, so foreach will fail.

desco
+1 For peeking in with reflector to see how the enumerators were implementing the check :)
Ani
A: 

Perhaps you could add them to a new list. Then at the end, outside the foreach use .addrange() to append the new ones to the original list.

Ashley