lambdas如何定位到局部变量?

Ant*_*ell 4 c# compiler-construction lambda

所以我对编译器如何处理lambdas的理解是有限的.

我的理解是编译器将你的lambda转换成一个真正的方法.

如果是这种情况那么它如何范围到局部变量?

    public async Task<dynamic> GetWebStuff()
    {
        dynamic ret = "";

        WebClient wc = new WebClient();          

        wc.DownloadStringCompleted += async (s, a) => 
        {
            ret = await Newtonsoft.Json.JsonConvert.DeserializeObject(a.Result.ToString());
        };

        wc.DownloadString("http://www.MyJson.com");

        return ret;
    }
Run Code Online (Sandbox Code Playgroud)

上面的示例将ret的返回值设置为调用者,调用者是反序列化JSON的动态对象.

如果编译器接受完成的事件lambda并将其抽象为自己的方法,那会怎样?如何知道设置ret值?

就像我说的那样(显然不会起作用)

        public async Task<dynamic> GetWebStuff()
        {
            dynamic ret = "";

            WebClient wc = new WebClient();

            wc.DownloadStringCompleted += wc_DownloadStringCompleted;            

            wc.DownloadString("google.com");

            return ret;
        }

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            ret = await Newtonsoft.Json.JsonConvert.DeserializeObject(e.Result.ToString());
        }
Run Code Online (Sandbox Code Playgroud)

Sel*_*enç 9

它确实创建了一个匿名类.例如,考虑以下代码:

int x = 0;

Action action = () => x = 2;

action();

Console.Write(x);
Run Code Online (Sandbox Code Playgroud)

并生成的类:

在此输入图像描述

<Main>b__2设置值的方法的IL代码x:

    .method assembly hidebysig instance void 
        '<Main>b__2'() cil managed
{
  // Code size       10 (0xa)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.2
  IL_0002:  stfld      int32 ConsoleApplication1.Program/'<>c__DisplayClass0'::x
  IL_0007:  br.s       IL_0009
  IL_0009:  ret
} // end of method '<>c__DisplayClass0'::'<Main>b__2'
Run Code Online (Sandbox Code Playgroud)

  • +1根据其他答案,它是一个闭包是正确的,但这就是它们在C#中实际实现的方式 (2认同)

P.B*_*key 5

我建议不要关注编译器如何做这样的事情,因为这是一个可以随时间变化的实现细节,而其他人已经说过不同的编译器实现(单声道?).相反,知道这样的事情是因为关闭而发生的.

在维基:

在编程语言中,闭包(也是词法闭包或函数闭包)是函数的一个函数或引用,以及一个引用环境 - 一个存储对每个非局部变量(也称为自由变量或上值)的引用的表.那个功能.1闭包 - 与普通函数指针不同 - 允许函数访问那些非局部变量,即使在其直接词法范围之外调用它也是如此.

  • 我想如果你理解关闭,你就不会这么说. (4认同)
  • 闭包定义解释了它的工作原理. (2认同)
  • 此外,理论上,不同平台中 C# 的不同实现可以以不同的方式处理规范。从根本上来说,有人可以用 lisp 实现 C# 语言。在这种情况下,lambda 将成为一等公民。如果您对 .NET 编译器如何处理 lambda 感兴趣,我认为问题中应该明确说明。 (2认同)