2016-02-16 14 views
5

ActionタイプとLambdasをC#でお試しください。ここに来るのコードは:あなたはそれが行に10、10倍を出力していることがわかりますこのコードを実行する場合はC#オブジェクトリファレンスとアクションタイプ

static void Main(string[] args) 
    { 
     List<Action> actions = new List<Action>(); 

     for (int I = 0; I < 10; I++) 
      actions.Add(new Action(() => Print(I.ToString()))); 

     foreach (Action a in actions) 
     { 
      a.Invoke(); 
     } 
     actions.Clear(); 

     int X; 
     for (X = 0; X < 10; X++) 
     { 
      int V = X; 
      actions.Add(new Action(() => Print(V.ToString()))); 
     } 

     foreach (Action a in actions) 
     { 
      a.Invoke(); 
     } 
     Console.ReadLine(); 
    } 


    public static void Print(string s) 
    { 
     Console.WriteLine(s); 
    } 

、その後、0から9の数字の周りに二回目を出力します。それは明らかに私がXと私が使用する方法と関係があり、2回目のループで毎回新しい変数Vに自分のアクションをどのように与えるのか...おそらく新しいVがそれぞれメモリ内の新しいアドレスですが、なぜI.ToString()が最初のループで同じことをしないのか理解するのに苦労しています...なぜ2番目の例と同じ方法で最初のActionで働くIToString()はありませんか?

+1

これは役に立ちます:http://stackoverflow.com/questions/3168375/using-the-iterator-variable-of-foreach-loop-in-a-lambda-expression-why-fails –

答えて

5

forループを効果的にコンパイラによってこれに出て展開されます。

{ 
    int I; 
    for (I = 0; I < 10; I++) 
    { 
    actions.Add(new Action(() => Print(I.ToString()))); 
    } 
} 

これは、すべてのラムダのインスタンスが10時にループが終了される、Iの同じインスタンスを取り込むことを意味します。

2番目の例では、forステートメントの本文にスコープされた変数に値をコピーし、ラムダはこのローカルを取得します。ループの繰り返しごとに固有のローカルがあります。

変数自体をキャプチャするのではなく、変数の値をキャプチャしないことが重要です。そのため、最初の例は機能しませんが、2番目の例は機能しません。 Action sは、あなたの最初のループ内に作成されている

+0

ありがとうございます。私はIToString()が新しい変数を作っていたと思ったでしょうが、明らかにそうではありません。関数呼び出しI.ToString()のようなものが格納され、Iの値は変更される可能性があり、呼び出されるまで評価されません。 –

2

これは単なるデリゲートであり、実際に呼び出すと実行され、呼び出されると、すべてのアクションは最後にiに設定された値を持ちますが、foreachループの場合はローカルになります値のコピーは、そのすべてのアクションは、それはあなたがforeachループでデリゲートを初めて起動すると、その時点iで内を持っているときi値が評価されます最初の例では、0〜9

を印刷しますそれ自身の価値を持っています2番目の例では、foreachループが値のローカルコピーを作成するので、foreachループによって行われる同じ動作を模倣するローカルに値を格納しています。

あなたはまたthis explanation of Jon Skeetを読むことができ、彼は2 eric lippertの投稿にリンクしています。これはあなたにもっと役立つでしょう。

+0

これははるかに優れています説明を受け入れた答えよりも。 – DGibbs

1

は、本当に保存されていることInvoke()メソッドの呼び出しが行われるまでは得られていないPrint()メソッドの呼び出しと変数Iの値であるが、これは後に発生しますループが終了し、変数Iは10の値を持ちます。

2番目のケースでは、新しい変数Vを各繰り返しで作成するので、それぞれの変数がその反復で作成されたV

関連する問題