哪个是创建捕获的变量/闭包的代码?

时间:2015-07-25 11:23:38

标签: c# .net clr dynamic-language-runtime

我知道变量捕获是由编译器完成的,而不是由.NET框架本身的类完成的。但是,当引入DLR时,必须在框架内完成一些工作,以便将其推迟到运行时。

例如,在下面给出的代码中:

dynamic d = ...

Func<int, bool> func = n => n > d;

变量d的类型解析及其验证是必须在运行时完成。由于d是lambda的contains方法中的变量,因此它将被捕获到闭包中。这部分肯定会在运行时完成。

因此,我推断必须有一部分DLR程序集(主要是 System.Core.dll )执行此部分。

我一直在寻找,我可以找到一些对这类任务看起来可疑的应受谴责的课程。具体来说,ExpressionQuoter(尽管它的外观,这个类不引用像Expression.Quote方法那样的lambda表达式),HoistedLocalsVariableBinder

我想我会邀请一个知道更好的人回答这个问题。

.NET框架的哪个类或部分将包含lambda(或匿名方法)方法的本地变成具有表示它们的静态变量的那些单独的类?

2 个答案:

答案 0 :(得分:2)

  

.NET框架的哪个类或部分会转换所在的本地文件   包含lambdas(或匿名方法)的方法   具有表示它们的静态变量的单独类?

不,它是完成这项工作的编译器。

  

如何将变量的值传递给单独的   方法?唯一的方法是定义一个新的辅助类   还为要传递给的每个值定义一个字段   回调代码。此外,必须定义回调代码   作为此助手类中的实例方法。然后,   UsingLocalVariablesInTheCallbackCode方法必须构造一个   辅助类的实例,从中的值初始化字段   它的局部变量,然后构造委托对象到   辅助对象/实例方法。

     

这是非常繁琐且容易出错的工作,当然, C#   编译器会自动为您完成所有这些

从书CLR Via 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#中的所有变量引用都静态绑定到特定变量,所以从不需要捕获动态数量的字段或类似的东西。要捕获的字段是静态知道的。