12

次のコードは、012 ではなく 33 を出力します。新しい変数 loopScopedi が、同じ変数をキャプチャするのではなく、各反復でキャプチャされない理由がわかりません。

Action[] actions = new Action[3];

for (int i = 0; i < 3; i++)
{

   actions [i] = () => {int loopScopedi = i; Console.Write (loopScopedi);};
}

foreach (Action a in actions) a();     // 333

ただし、このコードは 012 を生成します。この 2 つの違いは何ですか?

Action[] actions = new Action[3];

for (int i = 0; i < 3; i++)
{
    int loopScopedi = i;
    actions [i] = () => Console.Write (loopScopedi);
}

foreach (Action a in actions) a();     // 012
4

4 に答える 4

2

これは、C# がクロージャーを処理する方法に関するものです。最初の例では、クロージャーが正しくキャプチャされず、常に最後の値を使用することになります。しかし、2 番目の例では、ループ変数の現在の値をプレースホルダーにキャプチャしてから、そのプレースホルダーを使用します。適切なソリューションを提供します。

また、C# が foreach ループでループ変数をキャプチャする方法と、C# 5.0 と以前のバージョンの for ループでループ変数をキャプチャする方法には違いがあります。これは重大な変更です。

私は(ほとんど)同じ質問をしていて、ここでそれについて学びました。

于 2013-05-28T21:47:03.833 に答える
2

ラムダでキャプチャされた変数は、ラムダと外部コードの間で共有されるクラスに引き上げられます。

最初の例でiは、一度巻き上げられfor()、渡されたラムダとすべてのラムダの両方で使用されています。に到達するまでConsole.WriteLineに、はループからi到達しています。3for()

2番目の例では、ループの実行ごとに A newloopScopediが巻き上げられているため、後続のループの影響を受けません。

于 2013-05-28T21:45:25.713 に答える
2

2つの違いは何ですか?

スコープが異なります。

最初のループiでは、ループ ステートメント スコープで定義されている変数を参照していますforが、2 番目のループではローカル変数を使用しています。333 出力は、最初のループが 3 回繰り返され、それに応じてi変数が最終的に 3 にインクリメントされ、アクションを呼び出すと、すべてが同じ変数 ( i) を参照するという事実の結果です。

2 番目のループでは、それぞれ に新しい変数を使用しているActionため、012 が得られます。

于 2013-05-28T21:39:26.200 に答える