2015-11-20 19 views
6

私は常にこれらの2つの方法が類似していたと思いましたis:異なる結果が

[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
[YIELD] 11 
================== 
[LINQ] 1 
[LINQ] 2 
[LINQ] 3 
[LINQ] 4 
[LINQ] 5 
[LINQ] 6 
[LINQ] 7 
[LINQ] 8 
[LINQ] 9 
[LINQ] 10 

なぜですか?

答えて

6

これは閉鎖の問題です。この問題を解決するには、変数をループ内に格納する必要があります。実際new Func<int>(() => i);

for (int i = 1; i <= 10; i++) 
{ 
    var i1 = i; 
    yield return new Func<int>(() => i1); 
} 

は、ループ内のカウンタの正確な値を使用し、そのコピーではありません。したがって、ループが終了した後は、カウンタに設定された最後の値であるため、常に11になります。

+0

これはC#5.0以降の「修正済み」です。 http://stackoverflow.com/questions/12112881/has-foreachs-use-of-variables-been-changed-in-c-sharp-5 – juharr

+0

@juharr 'foreach'ループで変更されました。 'for 'ループは同じままです。 –

+0

@JakubLortz私の読書が床に落ちたので、間違いなく金曜日です。 – juharr

1

for(int i = 1; i <= 10; i++)iは、値を変更するだけで、各ループで同じ変数です。

() => iはクロージャです。呼び出されると、が作成されたときの値ではなく、iの値ではなく、現在の値がiになります。

返された関数を呼び出す前に、最初にGetFunctionsを列挙します。したがって、それぞれiはすでに11個です。あなたが列挙子からそれらを取得した後、すぐに関数を呼び出す場合

、あなたはLINQのバージョンと同じ結果が得られます:

foreach (var f in GetFunctions()) 
    Console.WriteLine("[YIELD2] {0}", f()); 

とにかく、それはループ変数の上にクロージャを作成するために、良いアイデアではありません。