2012-03-26 53 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