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), но он не срабатывает, и самое забавное, что он выводит:
Это было немного ожидаемо, но это указывает на то, что мы можем изменить, и это фактически меняет коллекцию. Есть идеи, почему возникает такое поведение?
c#
collections
Лежащий на небе
источник
источник
int.MaxValue
итераций занимает довольно много времени ...Ответы:
Проблема в том, что способ
List<T>
обнаружения модификаций заключается в сохранении поля версии типаint
, увеличивая его при каждой модификации. Следовательно, если вы внесли ровно несколько из 2 32 изменений в список между итерациями, это сделает эти изменения невидимыми с точки зрения обнаружения. (Он будет переполняться отint.MaxValue
доint.MinValue
и в конечном итоге вернется к своему исходному значению.)Если вы измените что-либо в своем коде - добавьте 1 или 3 значения, а не 2, или уменьшите количество итераций вашего внутреннего цикла на 1, тогда он выдаст исключение, как и ожидалось.
(Это деталь реализации, а не конкретное поведение - и это деталь реализации, которая может быть замечена как ошибка в очень редких случаях. Однако было бы очень необычно увидеть, как это вызывает проблему в реальной программе.)
источник
_version
полеint
.InvalidOperationException
, что на самом деле не всегда верно. Конечно, это зависит от определения «детали реализации».