使用lambda表达式时,c#中的闭包是如何工作的?

使用lambda表达式时,c#中的闭包是如何工作的?,c#,lambda,C#,Lambda,在下面的教程中: 他们说以下代码: for (int i = 0; i < 10; i++) new Thread (() => Console.Write (i)).Start(); for(int i=0;iConsole.Write(i)).Start(); 是不确定的,可以产生以下答案: 0223557799 我认为当使用lambda表达式时,编译器会创建某种匿名类,通过在捕获类中创建类似的成员来捕获正在使用的变量。 但是i是值类型,所以我认为他应该被值复制 我的错在

在下面的教程中:

他们说以下代码:

for (int i = 0; i < 10; i++)
  new Thread (() => Console.Write (i)).Start();
for(int i=0;i<10;i++)
新线程(()=>Console.Write(i)).Start();
是不确定的,可以产生以下答案:

0223557799

我认为当使用lambda表达式时,编译器会创建某种匿名类,通过在捕获类中创建类似的成员来捕获正在使用的变量。 但是
i
是值类型,所以我认为他应该被值复制

我的错在哪里


如果答案能够解释闭包是如何工作的,它是如何持有指向特定int的“指针”的,在这种特定情况下生成了什么代码,这将非常有帮助。

i
控制台中。Write(i)
在语句即将执行时正确计算。该语句将在线程完全创建并开始运行并访问该代码后执行。到那时,循环已经向前移动了几次,因此,
i
到那时可以是任何值。闭包不同于常规函数,它可以看到定义闭包的函数的局部变量(是什么使它们有用,以及如何自食其力)。

正如
Albahari
所述,尽管传递的参数是值类型,每个线程捕获
内存位置
,从而导致意外结果

这是因为在线程开始之前,循环已经更改了
i
中的任何值


为了避免这种情况,您应该使用
temp
变量,如
Albahari
所述,或者只在知道变量不会改变时使用它。

这里的关键点是闭包关闭变量,而不是关闭值。因此,关闭时给定变量的值是不相关的。重要的是调用匿名方法时该变量的值

当您看到编译器将闭包转换为什么时,就很容易看到这是如何发生的。它将创造出与此类似的道德:

public class ClosureClass1
{
    public int i;

    public void AnonyousMethod1()
    {
        Console.WriteLine(i);
    }
}

static void Main(string[] args)
{
    ClosureClass1 closure1 = new ClosureClass1();
    for (closure1.i = 0; closure1.i < 10; closure1.i++)
        new Thread(closure1.AnonyousMethod1).Start();
}

现在,
copy
变量在关闭后永远不会更改,我们的程序将输出0-9(尽管是以任意顺序,因为线程可以按照操作系统的需要进行调度)

在C#中,您希望捕获
i
的哪个值?尝试(inti=0;iConsole.Write(j)).Start();}@Lee,这是错误的。闭包语义没有任何变化。在C#的每个版本中,闭包都覆盖变量,而不是值(当然,闭包在1.0中根本不存在,但每个具有闭包的版本都有相同的语义)。@Lee-C#5中的变化特别是针对
foreach
迭代变量的变化<对于的code>一点也没有改变。这是一个参考资料,可以阅读更多关于这一点以及实际使用闭包代替值的效果(纯粹是假设性的)。
for (int i = 0; i < 10; i++)
{
    int copy = i;
    new Thread(() => Console.WriteLine(copy));
}