在匿名方法(lambda)中捕获的外部变量

Eva*_*Lin 1 .net c# lambda


我刚刚阅读了MSDN,发现这里需要任何建议。
http://msdn.microsoft.com/zh-CN/library/0yw3tz5k.aspx

创建委托时,将捕获对外部变量n的引用。与局部变量不同,捕获变量的生存期会延长,直到引用匿名方法的委托才有资格进行垃圾回收。

“已捕获”是否意味着将按值复制?但是我尝试编写一个示例程序,如下所示:

class Program
{

    class async_class
    {
        private int n = 0;

        public async_class()
        {
            for (int i = 0; i <= 9; i++)
            {
                System.Console.WriteLine("Outer  n={0} address={1}", n, n.GetHashCode());
                System.Threading.Thread thread1 = new System.Threading.Thread( () =>
                {
                    System.Console.WriteLine("Inner after n={0} address={1}", ++n, n.GetHashCode());
                });
                thread1.Start();
                //n = 10;
            }

        }

    }

    static void Main(string[] args)
    {
        async_class class1 = new async_class();
     }
}
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,内部“ ++ n”将写回原始外部“ n”。结果就是这样。

外部n = 0地址= 0
外部n = 0地址= 0
n = 1地址= 1之后的内部
外部n = 1地址= 1

任何人都可以解释有关“捕获的”外部变量的更多细节吗?

Ser*_*rvy 5

不,要说它已被捕获的全部目的是它只是复制值。闭包关闭变量,而不关闭。程序中的每一次访问n都访问相同的变量,因此永远不会有任何副本。

也就是说,您的程序是这种情况的一个令人困惑的例子。它使用多个线程,并引入了各种竞争条件,因为您不能安全地从多个线程操纵变量。这将导致各种不确定的行为。如果要研究闭包,请从单个线程进行研究;它将使您的程序变得非常容易理解。

你可以写很多简单的程序,证明封锁关闭了变量,而不是值。这是一个简单的代码段:

int n = 2;
Action a = () => Console.WriteLine(n);
n = 5;
a();
Run Code Online (Sandbox Code Playgroud)

如果闭包捕获到的值n,则将显示2。如果关闭该变量而不是其,则将显示5。继续运行并查看会发生什么。