1. ホーム
  2. シーピー

InvalidOperationExceptionが発生しました。「コレクションが変更されました。列挙操作の可能性があります。

2022-02-25 23:59:05
<パス

これは【C#チュートリアルのシリーズ28回目】です。役に立つと感じたら、自由にコラムをフォローしてください。

記事の目次

I: 問題の説明

foreachでリストに対してAddやRemoveの操作を行う場合、以下のようなコードになります。

class Program
{
    static List
 nameList = new List
();

    static void Main(string[] args)
    {
        nameList.Add("SuWake");
        nameList.Add("AllenSu");

        foreach (var name in nameList)
        {
        	nameList.Add("QingYuNian"); // add
            nameList.RemoveAt(0); // remove
        }
        Console.ReadKey();
    }
}


以下のようなエラーが報告されます。

II: ソリューション

次のコードのように、foreachをforループに変更するだけです。

for (int i = 0; i < nameList.Count; i++)
{
	nameList.Add("QingYuNian");
    nameList.RemoveAt(0);
}


III:なぜそうなるのか

参考1.
foreachは内部でIteratorを使用しているため、内部コードではまずhasNextかどうかを判断し、次にnextを呼び出しますが、この2つの関数が問題の原因となっています。

参考2.
foreach を使用してリストまたは辞書を検索する場合、Add または Remove 操作を実行するか、項目プロパティに値を代入すると、このエラーが発生します。

返された IEnumerator は現在のプロパティを読み取り専用として公開するため、それを変更すると実行時エラーになります。

特殊なケース
foreachで一括して追加や削除の操作を行った場合はこのエラーが発生しますが、最初の要素のみに対して操作を行い、操作後にブレークした場合は発生しません。

たとえば、ここでは、foreachで追加操作を行い、その時点でブレークしてリストの要素数を表示しています。

static void Main(string[] args)
{
	nameList.Add("SuWake");
    nameList.Add("AllenSu");

    foreach (var name in nameList)
    {
     	nameList.Add("QingYuNian");
        break;
    }
    
    Console.Write(nameList.Count);   
    Console.ReadKey();
}


コンソールを実行すると、次のような結果が得られます。

しかし、実際には誰もループの中で操作を行わないので、ここではそのようなテストになっています。

あなたの問題は解決しましたか?コメント欄に気軽にコメントを残してください。

記事が良いと思ったら、ワンクリック3連発をして頂けると幸いです、ありがとうございます。


<ブロッククオート

<センター 結論 <センター

技術は少しずつ積み重ねていくもので、神々には一日にして成らず。じっとしていると後退してしまうので、毎日少しずつ良くしていきましょう。
最後に、座右の銘として「善は急げ、忍びは急げ」を掲げました。