为什么这个C#程序输出这样的结果?我怎么理解关闭?

fer*_*anj 5 .net c# closures

我试图理解这个问题的答案为什么我在调用Func <int>时得到错误的结果?我写了一些示例代码.以下代码

public static void Main(string[] args)
{
    var funcs = new List<Func<string>>();
    for(int v=0,i=0;v<3;v++,i++)
    {
        funcs.Add( new Func<string>(delegate(){return "Hello "+ i++ +" "+v;}) );
    }
    foreach(var f in funcs)
        Console.WriteLine(f());
}
Run Code Online (Sandbox Code Playgroud)

产生

Hello 3 3
Hello 4 3
Hello 5 3
Run Code Online (Sandbox Code Playgroud)

在阅读了Jon Skeet和Eric Lippert的解释后,我想我会得到

Hello 3 3
Hello 3 3
Hello 3 3
Run Code Online (Sandbox Code Playgroud)

这里v和i都是循环变量,而i的值在那个瞬间被拾取v不是为什么这个?我不明白这种行为.

ang*_*son 11

好吧,你正确地理解了Eric和Jon,但是你错过了代码的一部分:

"Hello "+ i++ +" "+v;
          ^^^
          this part increments i for each call
Run Code Online (Sandbox Code Playgroud)

所以基本上,发生的事情与此类似:

  1. 捕获匿名函数3次,捕获方法中对变量的引用,而不是在循环范围内
  2. 在循环结束时,这两个变量的值均为3
  3. 执行所述第一功能时,输出的内容iv,然后递增i
  4. 执行第二功能,输出的内容iv和,因为这是同i为前面的方法调用,您将输出4在这里,没有3
  5. 等等

另一方面,如果您通过捕获循环范围内的变量来更改代码,如下所示:

for(int v=0,i=0;v<3;v++,i++)
{
    int ii = i, vv = v;
    funcs.Add( new Func<string>(delegate(){return "Hello "+ ii++ +" "+vv;}) );
}
Run Code Online (Sandbox Code Playgroud)

然后你会得到0, 0,1, 12, 2.你仍在增加ii变量,你在循环中使用捕获的值之后就这样做了,但是你再也不用那个变量了(每个匿名方法都有自己的私有副本.)感谢@ferosekhanj的评论