Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 即使在方法完成后,线程如何访问局部变量?_C#_Multithreading - Fatal编程技术网

C# 即使在方法完成后,线程如何访问局部变量?

C# 即使在方法完成后,线程如何访问局部变量?,c#,multithreading,C#,Multithreading,假设我有这样一个C#方法 public void MyMethod() { int i = 0; var thread = new Thread(() => { Thread.Sleep(100); if (i == 0) { Console.WriteLine("Value not changed and is {0}", i

假设我有这样一个C#方法

public void MyMethod()
    {
        int i = 0;

        var thread = new Thread(() =>
        {
            Thread.Sleep(100);

            if (i == 0)
            {
                Console.WriteLine("Value not changed and is {0}", i);
            }
            else
            {
                Console.WriteLine(" Value changed to {0}.", i);
            }
        });

        thread.Start();


        i = 1;
    }
这里方法创建一个线程,该线程访问在方法中创建的局部变量。 当它访问这个变量时,方法已经完成,因此局部变量i应该不存在。但是代码运行起来没有任何问题。据我所知,在方法块完成后,局部变量不存在。我无法得到它。

这称为a。

它将局部变量扩展到方法的生命周期之外。

这是有效的,因为编译器会重写您的代码以使用

由于在lambda中使用该变量,因此该变量最终会被更改为类的成员。编译后的代码不包含i的局部变量——即使您是这样编写的。相反,它重写代码以使用编译器生成的类,该类包含一个Int32作为成员变量,“本地代码”以及lambda引用该类成员


有关详细信息,请参阅这篇文章,它让您大致了解编译器在这里所做的工作

作为新线程启动的lambda表达式在i上创建一个;由于闭包在变量上关闭,而不是在值上关闭,因此线程引用与外部作用域相同的对象,并且即使在外部作用域结束后也能够访问其变量

据我所知,在方法块完成后,局部变量不存在。我无法得到这个

你的理解完全错误。局部变量的定义特征是其名称仅在其声明块内的作用域中。这就是为什么它被称为“局部”变量——因为它的名称只在局部可见

你相信“本地”意味着“短命”的谎言。这是不正确的;局部变量可以是短期变量,但有三种情况下它不能是短期变量:当它是匿名函数的封闭外部变量时,当它在迭代器块中时,或当它在异步块中时

巧合的是,你的问题是我上周博客的主题;有关更多详细信息,请参见:

C编译器通常将C代码转换为一种称为MSIL的中间“语言”,该语言与C一样具有局部变量。MSIL中的局部变量的行为与您期望的C#变量的行为相同:当定义它们的例程退出时,它们就不存在了。此外,当使用局部变量的C#代码被转换为使用局部变量的MSIL代码时,这些C#变量的行为类似于MSIL变量:当定义函数退出时,它们就不存在了。然而,并非所有使用局部变量的C#代码都使用MSIL局部变量来存储它们

在各种情况下,编译器将使用为使用局部变量而编写的代码,在将其转换为MSIL之前,将其重写,以便它定义一个新的类对象,该类对象包含相关变量的字段,然后重写对这些变量的访问,以便它们访问新字段。如果委托使用“变量”,则委托将获得对该新类对象的引用。即使定义对象的函数退出,只要任何对象(包括委托的任何副本)持有引用,对象本身也将继续存在


确定编译器何时使用MSIL局部变量以及何时重写内容以使用类字段的规则可能很棘手,对例程的一部分进行小的更改可能会改变其他看似不相关的部分的语义。

您会用什么术语来描述IL中用于保存未提升到类字段的变量的实体类型?从执行的角度来看,作为变量编写但保存在编译器类中的某些内容是一个类字段。@supercat:我将其称为局部变量。但我当时谈论的是MSIL语言,而不是C语言。出于好奇,你知道创建C语言的人是否考虑过要求闭包中使用的变量以声明方式标记?我认识到闭包是有用的,但隐式地将变量提升到闭包中似乎很危险,有时会产生不清楚的语义。明确声明闭包将使语义更加清晰。@supercat,如果您想要一种实现这一点的语言,请看C++11。它允许您显式指定lambda中可以使用的局部变量(如果需要)。