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

本文关键字:外部 变量 方法 lambda | 更新日期: 2023-09-27 17:54:46


我刚读了MSDN,在这里发现了一些需要建议的东西
http://msdn.microsoft.com/en-us/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();
     }
}
}

在此示例中,内部"++n"将写回原始外部"n"。所以结果会是。

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

有人可以解释"捕获">外部变量的更多细节吗?

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

不,说它被捕获的全部意义在于它是而不是只是复制值。闭包关闭变量,而不是。程序中n的每一次访问都在访问同一个变量,从来没有任何副本。

也就是说,你的程序是一个令人困惑的例子;它使用了多个线程,并且引入了各种竞争条件,因为您无法从多个线程安全地操作变量。这将导致各种未定义的行为。如果你想研究闭包,可以从一个线程开始;它将使你的程序更容易推理。

您可以编写更简单的程序来证明闭包关闭在变量上,而不是值上。这里有一个简单的片段:

int n = 2;
Action a = () => Console.WriteLine(n);
n = 5;
a();

如果闭包捕获了n的值,则会打印2。如果它关闭变量而不是其,它将打印5。继续运行它,看看会发生什么。