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)
它确实创建了一个匿名类.例如,考虑以下代码:
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闭包 - 与普通函数指针不同 - 允许函数访问那些非局部变量,即使在其直接词法范围之外调用它也是如此.