2012-03-26 69 views
1

可能重複:
Is there a reason for C#'s reuse of the variable in a foreach?
Looping through a list of ActionsC#關閉工程?

今天我遇到一個關於C#的foreach功能的問題,它並沒有給我正確的結果如我所料。這裏是代碼:

using System; 
using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     int[] data = new int[] { 1, 2, 3, 4, 5 }; 
     List<Func<int>> actions = new List<Func<int>>(); 
     foreach (int x in data) 
     { 
      actions.Add(delegate() { return x; }); 
     } 
     foreach (var foo in actions) 
     { 
      Console.WriteLine(foo()); 
     } 
     Console.ReadKey(); 
    } 
} 
} 

,當我在控制檯應用程序運行它,它可以打印在屏幕上5個5。爲什麼?我只是不明白。有人問過一些人,他們只是說這個代碼有閉包,但我對此不是很清楚,我記得在javascript中,我經常遇到閉包,但在上面的代碼中,爲什麼會有閉包?謝謝。

+3

查看:http://stackoverflow.com/questions/9569334/looping-through-a-list -of-actions/ – 2012-03-26 14:23:31

+2

http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – 2012-03-26 14:24:43

+0

幾乎每個人都會問這個問題天。請參閱http://stackoverflow.com/questions/8898925/is-there-a-reason-for-cs-reuse-of-the-variable-in-a-foreach/8899347#8899347瞭解有關此問題的良好討論。 – 2012-03-26 14:47:45

回答

6

在C#4 foreach循環份額的所有迭代相同的變量,並且因此相同閉合。

規範說:然後

foreach (V v in x) embedded-statement 

被擴展爲:

{ 
    E e = ((C)(x)).GetEnumerator(); 
    try 
    { 
    V v; 
    while (e.MoveNext()) 
    { 
     v = (V)(T)e.Current; 

     embedded-statement 
    } 
    } 
    finally 
    { 
    … // Dispose e 
    } 
} 

你可以看到,vwhile -loop外塊,這將導致此聲明分享行爲。

這可能會在C#5被改變。

我們正在採取的重大更改。在C#5中,foreach的循環變量將在邏輯上處於循環內部,因此每次關閉變量的新副本時都會關閉。 「for」循環不會被改變。

http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

+0

爲什麼這個早期規範說V是while循環http://msdn.microsoft.com/en-GB/library/aa664754內部聲明。aspx – colinfang 2013-04-29 16:03:57

2

的關鍵是,當你在你的foreach循環中產生代表你是整個環變量x創建一個封閉,不是它的當前值

只有當你在actions執行代表將值來確定,這在當時是的x。由於您已經完成了foreach循環,因此該值將是您的data數組中的最後一項,即數組爲5時的最後一項。

+0

+1:非常清晰簡潔的解釋。 – phoog 2012-03-26 14:27:59

+1

重要的是要注意,最後一句只適用於C#4及更早的版本。 – CodesInChaos 2012-03-26 14:35:32

+0

..你已經指出了,所以我不想重複它;-) – BrokenGlass 2012-03-26 14:40:15