Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this code throws 'Collection was modified', but when I iterate something before it, it doesn't?

Tags:

c#

collections

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;
}

If you comment out the inner for loop, it throws, it's obviously because we did changes to the collection.

Now if you uncomment it, why this loop allow us to add those two items? It takes awhile to run it like half a minute (On Pentium CPU), but it doesn't throw, and the funny thing is that it outputs:

Image

It was a bit of expected, but it indicates that we can change and it actually changes the collection. Any ideas why this behaviour occuring?

like image 657
LyingOnTheSky Avatar asked Nov 03 '14 16:11

LyingOnTheSky


People also ask

Which does not allow collection modification while iterating?

One big reason for not allowing modification of a collection while iterating on it is that, if elements in the collection are deleted or if new elements are inserted, it will throw the iteration off. (An element was inserted or deleted right where the iteration is working in the collection; what's the next element now?


1 Answers

The problem is that the way that List<T> detects modifications is by keeping a version field, of type int, incrementing it on each modification. Therefore, if you've made exactly some multiple of 232 modifications to the list between iterations, it will render those modifications invisible as far as detection is concerned. (It will overflow from int.MaxValue to int.MinValue and eventually get back to its initial value.)

If you change pretty much anything about your code - add 1 or 3 values rather than 2, or lower the number of iterations of your inner loop by 1, then it will throw an exception as expected.

(This is an implementation detail rather than specified behaviour - and it's an implementation detail which can be observed as a bug in a very rare case. It would be very unusual to see it cause a problem in a real program, however.)

like image 176
Jon Skeet Avatar answered Oct 13 '22 20:10

Jon Skeet