Добавление узлов в LinkedList <T>в foreach - PullRequest
5 голосов
/ 08 августа 2010

Можно ли безопасно добавить узлы в контейнер LinkedList внутри оператора foreach? Есть ли разница, если я использовал цикл while? Или это никогда не допускается и может вызвать некоторые проблемы?

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

Будет ли всегда работать?

Ответы [ 4 ]

6 голосов
/ 08 августа 2010

Вы не можете изменять коллекцию, пока перечисляете ее.

Из документов для LinkedList<T>.GetEnumerator:

Перечислитель остается в силе до тех пор, пока коллекция остается без изменений. Если внесены изменения в коллекцию, такие как добавление, изменение или удаление элементы, перечислитель безвозвратно признан недействительным и его поведение не определено.

На практике я считаю, что он всегда выдаст InvalidOperationException, несмотря на то, что поведение официально не определено.

EDIT: Вы спросили в комментарии, поможет ли цикл while ... цикл while с использованием GetEnumerator / MoveNext / Current не поможет, но это будет:

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

Насколько я знаю, это абсолютно безопасно и предсказуемо. Вы всегда можете запросить у узла следующий узел. Если вам случится посмотреть на хвостовой узел и добавить еще один, вы получите новый хвостовой узел, когда попросите «следующий».

Если это не поможет, пожалуйста, дайте нам более подробную информацию о том, чего вы пытаетесь достичь.

2 голосов
/ 08 августа 2010

Нет, объект перечислителя запоминает внутреннюю версию собственной коллекции. После изменения коллекции - изменилась версия, поэтому foreach завершится ошибкой.

1 голос
/ 08 августа 2010

Перебирая коллекцию с помощью оператора foreach, вы не можете ее изменить.Таким образом, добавление элементов приведет к ошибке компилятора.

0 голосов
/ 10 августа 2010

Возможно, вы могли бы добавить их в новый список.Затем в конце за пределами foreach используйте .addrange () , чтобы добавить новые в исходный список.

...