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
循环,它会抛出,显然是因为我们对集合进行了更改。
现在,如果您取消注释,为什么这个循环允许我们添加这两个项目?它需要一段时间才能运行半分钟(在奔腾CPU上),但它不会抛出,有趣的是它输出:
这有点预期,但它表明我们可以改变,它实际上改变了收藏。有没有想过为什么会出现这种情况?
答案 0 :(得分:119)
问题在于List<T>
检测修改的方式是保留类型为int
的版本字段,并在每次修改时递增它。因此,如果您已经在迭代之间对列表进行了完全 2个 32 修改的某些倍数,那么就检测而言,它将使这些修改不可见。 (它会从int.MaxValue
溢出到int.MinValue
并最终恢复到初始值。)
如果你几乎改变了你的代码 - 添加1或3个值而不是2,或者将内循环的迭代次数减少1,那么它将按预期抛出异常。
(这是一个实现细节,而不是指定的行为 - 它是一个实现细节,在极少数情况下可以被视为一个错误。看到它导致实际问题是非常不寻常的。然而,程序。)