我知道变量捕获是由编译器完成的,而不是由.NET框架本身的类完成的。但是,当引入DLR时,必须在框架内完成一些工作,以便将其推迟到运行时。
例如,在下面给出的代码中:
dynamic d = ...
Func<int, bool> func = n => n > d;
变量d
的类型解析及其验证是必须在运行时完成。由于d
是lambda的contains方法中的变量,因此它将被捕获到闭包中。这部分肯定会在运行时完成。
因此,我推断必须有一部分DLR程序集(主要是 System.Core.dll )执行此部分。
我一直在寻找,我可以找到一些对这类任务看起来可疑的应受谴责的课程。具体来说,ExpressionQuoter(尽管它的外观,这个类不引用像Expression.Quote
方法那样的lambda表达式),HoistedLocals和VariableBinder。
我想我会邀请一个知道更好的人回答这个问题。
.NET框架的哪个类或部分将包含lambda(或匿名方法)方法的本地变成具有表示它们的静态变量的那些单独的类?
答案 0 :(得分:2)
.NET框架的哪个类或部分会转换所在的本地文件 包含lambdas(或匿名方法)的方法 具有表示它们的静态变量的单独类?
不,它是完成这项工作的编译器。
如何将变量的值传递给单独的 方法?唯一的方法是定义一个新的辅助类 还为要传递给的每个值定义一个字段 回调代码。此外,必须定义回调代码 作为此助手类中的实例方法。然后, UsingLocalVariablesInTheCallbackCode方法必须构造一个 辅助类的实例,从中的值初始化字段 它的局部变量,然后构造委托对象到 辅助对象/实例方法。
这是非常繁琐且容易出错的工作,当然, C# 编译器会自动为您完成所有这些
使用您的代码,生成了一个类似于:
的类class SomeClass
{
public dynamic d;
public bool yourCallBack(int n)
{
return n > d;
}
}
并且您的代码编译成类似于:
dynamic d = ...
SomeClass class1= new SomeClass();
class1.d = d;
Func<int, bool> func = class1.yourCallBack;
还有关于捕获变量的生命周期的说明:
当lambda表达式导致编译器生成一个类时 参数/局部变量变成了字段,生命周期 变量引用的对象被延长。 通常,a 参数/局部变量超出了最后一次使用的范围 方法中的变量。但是,将变量转换为字段 导致该字段将其引用的对象保持为活动状态 包含字段的对象的整个生命周期。这不是一个大问题 处理大多数应用程序,但它应该是你应该做的 意识到了。
答案 1 :(得分:0)
由于d是lambda的contains方法中的变量,因此它将被捕获到闭包中。
d
不需要被捕获,因为lambda没有使用它。如果C#编译器选择捕获它(在as-if规则下不被禁止),则不会以任何方式访问它。
我相信func(d)
的执行方式与使用动态参数的任何方法调用一样。
让我们来看看:
dynamic d = ...; //maybe "1"
Func<bool> func = (() => d == "1234");
我认为这更符合你想要知道的精神(更新:事实上你刚刚编辑了这个模式的问题)。 lambda现在取决于d
,而以前并非如此。
这里,d
在生成的闭包类中被捕获为object
类型的字段。 dynamic
始终编译为object
(可能包含自定义属性)。然后lambda代码体继续使用标准的动态操作。
因为C#中的所有变量引用都静态绑定到特定变量,所以从不需要捕获动态数量的字段或类似的东西。要捕获的字段是静态知道的。