为什么这段代码会被修改' Collection被修改了#39;但是当我在它之前迭代一些东西时,它并没有?

时间:2014-11-03 16:53:32

标签: 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;
}

如果您注释掉内部for循环,它会抛出,显然是因为我们对集合进行了更改。

现在,如果您取消注释,为什么这个循环允许我们添加这两个项目?它需要一段时间才能运行半分钟(在奔腾CPU上),但它不会抛出,有趣的是它输出:

Image

这有点预期,但它表明我们可以改变,它实际上改变了收藏。有没有想过为什么会出现这种情况?

1 个答案:

答案 0 :(得分:119)

问题在于List<T>检测修改的方式是保留类型为int的版本字段,并在每次修改时递增它。因此,如果您已经在迭代之间对列表进行了完全 2个 32 修改的某些倍数,那么就检测而言,它将使这些修改不可见。 (它会从int.MaxValue溢出到int.MinValue并最终恢复到初始值。)

如果你几乎改变了你的代码 - 添加1或3个值而不是2,或者将内循环的迭代次数减少1,那么它将按预期抛出异常。

(这是一个实现细节,而不是指定的行为 - 它是一个实现细节,在极少数情况下可以被视为一个错误。看到它导致实际问题是非常不寻常的。然而,程序。)