2010-08-08 12 views
5

Czy mogę bezpiecznie dodawać węzły do ​​kontenera LinkedList wewnątrz instrukcji foreach? Czy jest jakaś różnica, jeśli użyłem pętli? Czy to nigdy nie jest dozwolone i może powodować problemy?Dodawanie węzłów do LinkedList <T> w foreach

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

Będzie zawsze pracy?

Odpowiedz

6

Nie można zmodyfikować kolekcji podczas jej wyliczania.

Z docs for LinkedList<T>.GetEnumerator:

Numerator zachowuje ważność tak długo, jak kolekcja pozostaje niezmieniona. Jeśli do kolekcji zostaną wprowadzone zmiany , takie jak dodawanie, modyfikowanie lub usuwanie elementów , moduł wyliczający zostanie nieodwracalnie unieważniony, a jego zachowanie zostanie niezdefiniowane.

W praktyce uważam, że zawsze będzie rzutować InvalidOperationException, mimo że oficjalnie zachowanie jest niezdefiniowane.

EDIT: Pytałeś w komentarzu czy while pętla pomogłoby ... pętlę podczas używania GetEnumerator/MoveNext/Current nie, ale to będzie:

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

O ile jestem świadomy, że jest całkowicie bezpieczny i przewidywalny. Zawsze możesz poprosić węzeł o kolejny węzeł. Jeśli zdarzy ci się patrzeć na węzeł końcowy i dodać kolejny, otrzymasz nowy węzeł końcowy, gdy poprosisz o "następny".

Jeśli to nie pomoże, proszę podać nam więcej informacji o tym, co próbujesz osiągnąć.

+0

Całkowicie bezpieczne to rozciągnięta, nieskończona pętla i OOM, jeśli nowy węzeł dopasuje warunek. –

1

Podczas iteracji nad kolekcją z instrukcją foreach, nie można jej zmodyfikować. Dlatego dodanie elementów spowoduje błąd kompilatora.

+0

będzie używać pętli "while" rozwiązać mój problem? –

+1

Możesz użyć pętli 'while' do zapętlenia kolekcji. Podczas wykonywania tej operacji nie otrzymasz błędu kompilatora, ale uważaj, aby nie pisać nieskończonej pętli - co może się zdarzyć, jeśli nowa funkcja 'MyNode()' spełni "warunek". –

+3

It * nie spowoduje * błędu kompilatora. Podany kod skompiluje się bez problemu. Wyrzuci wyjątek w czasie wykonywania. –

2

Nie, obiekt modułu wyliczającego zapamiętuje wewnętrzną wersję kolekcji własnej. Po zebraniu jest zmodyfikowana - wersja zmieniona, więc foreach się nie powiedzie.

+0

+1 Do podglądania za pomocą reflektora, aby zobaczyć, w jaki sposób rachmistrze realizują czek :) – Ani

0

Być może możesz dodać je do nowej listy. Następnie na końcu, poza foreach użyj .addrange(), aby dołączyć nowe do oryginalnej listy.

Powiązane problemy