为什么这个代码抛出'集合被修改',但是当我迭代它之前的东西,它不?

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

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

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

图片

这是有点期待,但它表明我们可以改变,实际上改变了收集。 任何想法,为什么这种行为发生?

问题是List<T>检测修改的方式是保留一个inttypes的版本字段,在每次修改时递增它。 因此,如果在迭代之间已经对列表进行了2 32次修改,那么就会在检测过程中使这些修改不可见。 (它会从int.MaxValue溢出到int.MinValue并最终返回到它的初始值。)

如果你改变了你的代码几乎所有的东西 – 添加1或3的值而不是2,或者减less内部循环的迭代次数1,那么它会抛出一个exception,如预期的那样。

(这是一个实现细节,而不是指定的行为 – 这是一个实现细节,在一个非常罕见的情况下,它可以被视为一个错误。但是,在一个真正的程序中看到这个错误是非常罕见的。