このコードが「コレクションが変更されました」をスローするのはなぜですか?


102
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ループをコメントアウトすると、スローされます。コレクションに変更を加えたためです。

コメントを外した場合、なぜこのループでこれら2つの項目を追加できるのでしょうか。30分ほど(Pentium CPUの場合)のように実行するのには少し時間がかかりますが、スローされず、面白いのは次のように出力されることです。

画像

少し予想通りでしたが、変更できることと実際にコレクションが変更されることを示しています。この動作が発生する理由はありますか?


2
それは面白い。動作を再現できましたが、内部ループをInt.MaxValueから100のような値に変更した場合は不可能でした
Steve

どのくらい待った?int.MaxValueイテレーションの完了にはかなり時間がかかります...
Jon Skeet

1
foreachは、各ループの最初でコレクションが変更されているかどうかをチェックするので、各ループ内でアイテムを追加してから削除してもエラーは発生しません。
Kaz

6
参照ソースを見て、変更検出がどのように機能するかを確認することで、この質問に自分で答えることができたかもしれません。誰もが参照ソースが存在することさえ知っているわけではなく、単に言葉を広めるだけです:)
Christopher Currens 2014年

2
ちょうど好奇心から:この問題は実際のコードで発生しましたか?
ken2k 2014年

回答:


119

問題は、List<T>変更を検出する方法が、タイプのバージョンフィールドを保持し、int変更ごとに増分することです。したがって、反復の間にリストに2 32の倍数の修正を正確に加えた場合、検出に関する限り、それらの修正は非表示になります。(それはto からオーバーフローし、最終的にその初期値に戻ります。)int.MaxValueint.MinValue

コードについてほとんど何も変更しない場合-2ではなく1または3の値を追加するか、内部ループの反復回数を1減らします。期待どおりに例外がスローされます。

(これは指定された動作ではなく実装の詳細です-非常にまれなケースでバグとして観察できる実装の詳細です。ただし、実際のプログラムで問題が発生することは非常にまれです。)


5
参考までに、関連するソースコード_versionフィールドがであることに注意してくださいint
Lucas Trzesniewski、2014年

1
うん、forループが終了した後、_versionの値が-2になるように正しく設定されています。次に、6と7を追加すると0になり、リストは変更されていないように見えます。
Kaz

4
これが「実装の詳細」と呼ばれるべきかどうかはわかりません。実装の決定には副作用があり、それが起こる可能性は低いとしても、それが現実であるためです。仕様(または少なくともドキュメント)はをスローする必要があると述べてInvalidOperationExceptionいますが、実際には常にそうであるとは限りません。もちろん、これは「実装の詳細」の定義に依存します。
ken2k 2014年

3
ジョン・スキート、プログラミング言語デザイナーですか?(Googleに関連するものは何も見つかりませんでした)なぜあなたもこの知識を持っているのか少し気になります。この質問は、スタックオーバーフローの「力」を見るのに少々いじめでした。
LyingOnTheSky 2014年

6
@LyingOnTheSky:いいえ。ただし、C#言語をフォロ​​ーして批評するという点では、言語デザイナーであることが好きです。私はまた、C#5を標準化するためのECMA-334テクニカルグループに所属しています。そのため、穴をあけることができますが、実際の言語設計作業は行えません:)
Jon Skeet
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.