1. ホーム
  2. c#

[解決済み] なぜList<T>.ForEachはリストの変更を許可するのですか?

2023-04-17 05:35:15

質問

を使用する場合。

var strings = new List<string> { "sample" };
foreach (string s in strings)
{
  Console.WriteLine(s);
  strings.Add(s + "!");
}

その Add の中に foreach は InvalidOperationException (Collection was modified; enumeration operation may not execute) をスローしますが、これは足元からラグを引っ張っているため、論理的だと考えています。

しかし、私が使用すると

var strings = new List<string> { "sample" };
strings.ForEach(s =>
  {
    Console.WriteLine(s);
    strings.Add(s + "!");
  });

を実行すると、すぐに OutOfMemoryException を投げるまでループして、自分自身の足を撃ってしまいます。

私はいつも、List.ForEach は単に、List.ForEach のラッパーだと考えていたので、これは私にとって驚きです。 foreach または for .

どなたか、この動作の方法と理由を説明できる方はいらっしゃいませんか?

(インスパイアード・バイ Generic ListのForEachループが延々と繰り返される )

どのように解決するのですか?

それは ForEach メソッドは列挙子を使用せず、項目をループして for ループを使用します。

public void ForEach(Action<T> action)
{
    if (action == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    for (int i = 0; i < this._size; i++)
    {
        action(this._items[i]);
    }
}

(JustDecompileで取得したコード)

列挙子は使われないので、リストが変更されたかどうかをチェックすることはなく、終了条件の for ループの終了条件に達することはありません。 _size は反復毎に増加するため、ループに到達することはありません。