Почему этот код выдает "Коллекция была изменена", но когда я что-то повторяю перед ней, это не так?
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;
}
Если вы закомментируете внутренний for
цикл, это бросает, это очевидно, потому что мы сделали изменения в коллекции.
Теперь, если вы раскомментируете это, почему этот цикл позволяет нам добавлять эти два элемента? Требуется некоторое время, чтобы запустить его как полминуты (на процессоре Pentium), но он не выдает, и самое забавное, что он выдает:
Это было немного ожидаемым, но это указывает на то, что мы можем измениться, и это фактически меняет коллекцию. Есть идеи, почему такое поведение происходит?
1 ответ
Проблема в том, что способ, которым List<T>
обнаруживает изменения, сохраняя поле версии, типа int
увеличивая его на каждую модификацию. Поэтому, если вы сделали ровно несколько кратных из32 модификаций в списке между итерациями, он сделает эти модификации невидимыми в отношении обнаружения. (Это будет переполнено из int.MaxValue
в int.MinValue
и в конечном итоге вернуться к своему первоначальному значению.)
Если вы в значительной степени измените свой код - добавьте 1 или 3 значения вместо 2 или уменьшите число итераций вашего внутреннего цикла на 1, тогда это приведет к ожидаемому исключению.
(Это деталь реализации, а не указанное поведение - и это деталь реализации, которая может быть замечена как ошибка в очень редком случае. Однако было бы очень необычно видеть, что это вызывает проблему в реальной программе.)