使用lambda表达式时,如何关闭在C#中的作品? [英] How closure in c# works when using lambda expressions?

查看:128
本文介绍了使用lambda表达式时,如何关闭在C#中的作品?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为下面的教程: http://www.albahari.com/threading/

他们说,下面的代码:

for (int i = 0; i < 10; i++)
  new Thread (() => Console.Write (i)).Start();



是不确定性的,可以产生以下的回答:

is non deterministic and can produce the following answer :

0223557799

0223557799

我想,当一个人使用Lambda表达式编译器创建某种匿名类捕获正在使用由捕获类创建成员和他们一样的变量。
,而 I 是值类型,所以我想他应该值被复制。

I thought that when one uses lambda expressions the compiler creates some kind of anonymous class that captures the variables that are in use by creating members like them in the capturing class. But i is value type, so i thought that he should be copied by value.

在哪里是我的错?

这将是非常有益的,如果答案将解释如何做堵口,如何做到这一点举行指针到特定的INT,并在这一特定产生什么代码这样吗?

It will be very helpful if the answer will explain how does closure work, how do it hold a "pointer" to a specific int , what code does generated in this specific case ?

推荐答案

这里的关键点是,封关过的变量,没有结束值的。这样,在给定时间可变的关闭在它的值是不相关的。要紧的是变量的值的在匿名方法被调用

The key point here is that closures close over variables, not over values. As such, the value of a given variable at the time you close over it is irrelevant. What matters is the value of that variable at the time the anonymous method is invoked.

这是如何发生的时间是很容易看到,当你看到什么编译器转换封盖进入。这将创建一个在道德上类似于这样:

How this happens is easy enough to see when you see what the compiler transforms the closure into. It'll create something morally similar to this:

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();
}



所以在这里我们可以看到一点更清楚发生了什么事情。有可变的一个副本,而现在这个变量已被提升为一类新的场,而不是被局部变量。任何地方,将修改局部变量现在修改该实例的领域。现在,我们可以看到,为什么你的代码打印它做什么。启动后新的线程,但它实际上可以执行之前,在主线程中的循环回去和增量在封闭的变量。这还没有读经闭的变量。

So here we can see a bit more clearly what's going on. There is one copy of the variable, and that variable has now been promoted to a field of a new class, instead of being a local variable. Anywhere that would have modified the local variable now modifies the field of this instance. We can now see why your code prints what it does. After starting the new thread, but before it can actually execute, the for loop in the main thread is going back and incrementing the variable in the closure. The variable that hasn't yet been read by the closure.

要生产,而不必的每次迭代所期望的结果,你需要做的是确保,合环在一个单可变,他们需要将每个具有可变的,它们关闭超过

To produce the desired result what you need to do is make sure that, instead of having every iteration of the loop closing over a single variable, they need to each have a variable that they close over:

for (int i = 0; i < 10; i++)
{
    int copy = i;
    new Thread(() => Console.WriteLine(copy));
}

现在的复制它被关闭了后变量没有改变,和我们的程序将打印出0-9(虽然以任意的顺序,因为线程可以被调度但是在OS希望)。

Now the copy variable is never changed after it is closed over, and our program will print out 0-9 (although in an arbitrary order, because threads can be scheduled however the OS wants).

这篇关于使用lambda表达式时,如何关闭在C#中的作品?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆