var ints = new List< int >( new[ ] {
1,
2,
3,
4,
5
} );
var first = true;
foreach( var v in ints ) {
if ( first ) {
for ( long i = 0 ; i < int.MaxValue ; ++i ) { //<-- The thing I iterate
ints.Add( 1 );
ints.RemoveAt( ints.Count - 1 );
}
ints.Add( 6 );
ints.Add( 7 );
}
Console.WriteLine( v );
first = false;
}
Jeśli skomentujesz wewnętrzną for
pętlę, zostanie ona wyrzucona , jest to oczywiście spowodowane zmianami w kolekcji.
Jeśli teraz odkomentujesz to, dlaczego ta pętla pozwala nam dodać te dwa elementy? Trwa trochę czasu, aby uruchomić go jak pół minuty (na procesorze Pentium), ale nie rzuca się, a zabawne jest to, że wyświetla:
Było to trochę oczekiwane, ale wskazuje, że możemy się zmienić i to faktycznie zmienia kolekcję. Jakieś pomysły, dlaczego takie zachowanie występuje?
c#
collections
LyingOnTheSky
źródło
źródło
int.MaxValue
iteracji zajmuje trochę czasu ...Odpowiedzi:
Problem polega na tym, że sposobem
List<T>
wykrywania modyfikacji jest zachowanie pola wersji, typuint
i zwiększanie go przy każdej modyfikacji. Dlatego, jeśli dokonałeś dokładnie wielokrotności 2 32 modyfikacji listy między iteracjami, spowoduje to, że te modyfikacje będą niewidoczne, jeśli chodzi o wykrywanie. (Przepełni się zint.MaxValue
doint.MinValue
i ostatecznie powróci do swojej wartości początkowej).Jeśli zmienisz prawie wszystko w swoim kodzie - dodasz 1 lub 3 wartości zamiast 2 lub zmniejsz liczbę iteracji wewnętrznej pętli o 1, to zgłosi wyjątek zgodnie z oczekiwaniami.
(Jest to raczej szczegół implementacji niż określone zachowanie - i jest to szczegół implementacji, który można zaobserwować jako błąd w bardzo rzadkich przypadkach. Jednak byłoby bardzo nietypowe, gdyby spowodował problem w prawdziwym programie).
źródło
_version
pole toint
.InvalidOperationException
, co w rzeczywistości nie zawsze jest prawdą. Oczywiście zależy to od definicji „szczegółów implementacji”.