哪个是创建捕获变量/闭包的代码?
Which is the code that creates captured variables / closures?
我知道变量捕获是由编译器完成的,而不是由 .NET 框架本身中的 classes 完成的。但是,在引入 DLR 时,其中一些工作肯定需要在框架内完成,以便推迟到 运行 时间。
例如,在下面给出的代码段中:
dynamic d = ...
Func<int, bool> func = n => n > d;
变量 d
的类型解析及其是否为整数的验证必须在 运行 时完成。由于 d
是 lambda 包含方法中的一个变量,它将被捕获到一个闭包中。这部分肯定会在运行时间完成。
因此,我推断一定有某些 DLR 组件(System.Core.dll 大部分)执行此部分。
我一直在搜索,我可以找到一些看起来可疑地应受谴责的此类任务的 classes。具体来说,ExpressionQuoter (despite the looks of it, this class does not quote lambda expressions like the Expression.Quote
method does), HoistedLocals, and the VariableBinder.
我想我会邀请更了解的人来回答这个问题。
哪个 class 或 .NET 框架的一部分将包含 lambda 方法(或匿名方法)的局部变量转换为具有表示它们的静态变量的单独 classes?
Which class or part of the .NET framework turns locals that are in
containing methods of lambdas (or anonymous methods) into those
separate classes that have static variables representing them?
不,是编译器在做这项工作。
How would the values of the variables be passed to the separate
method? The only way to do this is to define a new helper class that
also defines a field for each value that you want passed to the
callback code. In addition, the callback code would have to be defined
as an instance method in this helper class. Then, the
UsingLocalVariablesInTheCallbackCodemethod would have to construct an
instance of the helper class,initialize the fields fromthe values in
its local variables, and then construct the delegate objectbound to
the helper object/instance method.
This is very tedious and error-prone work, and, of course, the C#
compiler does all this for you automatically
来自书本CLR Via C#
使用您的代码,生成的 class 看起来像:
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;
关于捕获变量的生命周期还有一个注意事项:
When a lambda expression causes the compiler to generate a class with
parameter/local variables turned into fields, the lifetime of the
objects that the variables refer to are lengthened. Usually, a
parameter/local variable goes out of scope at the last usage of the
variable within a method. However, turning the variable into a field
causes the field to keep the object that it refers to alive for the
whole lifetime of the object containing the field. This is not a big
deal in most applications, but it is something that you should be
aware of.
And since d is a variable in the containing method of the lambda, it will be captured into a closure.
d
不需要捕获,因为 lambda 没有使用它。如果 C# 编译器选择捕获它(在 as-if 规则下不被禁止),它将不会以任何方式被访问。
我相信 func(d)
的执行方式与任何带有动态参数的方法调用一样。
我们来看看:
dynamic d = ...; //maybe "1"
Func<bool> func = (() => d == "1234");
我认为这更符合您想知道的内容(更新:实际上您只是编辑了问题以具有此模式)。 lambda 现在取决于 d
而以前不是这样。
这里,d
在生成的闭包 class 中被捕获为类型 object
的字段。 dynamic
总是编译为 object
(可能带有自定义属性)。然后 lambda 代码主体继续使用标准动态操作。
因为 C# 中的所有变量引用都静态绑定到特定变量,所以永远不需要捕获动态数量的字段或类似的东西。要捕获的字段是静态已知的。
我知道变量捕获是由编译器完成的,而不是由 .NET 框架本身中的 classes 完成的。但是,在引入 DLR 时,其中一些工作肯定需要在框架内完成,以便推迟到 运行 时间。
例如,在下面给出的代码段中:
dynamic d = ...
Func<int, bool> func = n => n > d;
变量 d
的类型解析及其是否为整数的验证必须在 运行 时完成。由于 d
是 lambda 包含方法中的一个变量,它将被捕获到一个闭包中。这部分肯定会在运行时间完成。
因此,我推断一定有某些 DLR 组件(System.Core.dll 大部分)执行此部分。
我一直在搜索,我可以找到一些看起来可疑地应受谴责的此类任务的 classes。具体来说,ExpressionQuoter (despite the looks of it, this class does not quote lambda expressions like the Expression.Quote
method does), HoistedLocals, and the VariableBinder.
我想我会邀请更了解的人来回答这个问题。
哪个 class 或 .NET 框架的一部分将包含 lambda 方法(或匿名方法)的局部变量转换为具有表示它们的静态变量的单独 classes?
Which class or part of the .NET framework turns locals that are in containing methods of lambdas (or anonymous methods) into those separate classes that have static variables representing them?
不,是编译器在做这项工作。
How would the values of the variables be passed to the separate method? The only way to do this is to define a new helper class that also defines a field for each value that you want passed to the callback code. In addition, the callback code would have to be defined as an instance method in this helper class. Then, the UsingLocalVariablesInTheCallbackCodemethod would have to construct an instance of the helper class,initialize the fields fromthe values in its local variables, and then construct the delegate objectbound to the helper object/instance method.
This is very tedious and error-prone work, and, of course, the C# compiler does all this for you automatically
来自书本CLR Via C#
使用您的代码,生成的 class 看起来像:
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;
关于捕获变量的生命周期还有一个注意事项:
When a lambda expression causes the compiler to generate a class with parameter/local variables turned into fields, the lifetime of the objects that the variables refer to are lengthened. Usually, a parameter/local variable goes out of scope at the last usage of the variable within a method. However, turning the variable into a field causes the field to keep the object that it refers to alive for the whole lifetime of the object containing the field. This is not a big deal in most applications, but it is something that you should be aware of.
And since d is a variable in the containing method of the lambda, it will be captured into a closure.
d
不需要捕获,因为 lambda 没有使用它。如果 C# 编译器选择捕获它(在 as-if 规则下不被禁止),它将不会以任何方式被访问。
我相信 func(d)
的执行方式与任何带有动态参数的方法调用一样。
我们来看看:
dynamic d = ...; //maybe "1"
Func<bool> func = (() => d == "1234");
我认为这更符合您想知道的内容(更新:实际上您只是编辑了问题以具有此模式)。 lambda 现在取决于 d
而以前不是这样。
这里,d
在生成的闭包 class 中被捕获为类型 object
的字段。 dynamic
总是编译为 object
(可能带有自定义属性)。然后 lambda 代码主体继续使用标准动态操作。
因为 C# 中的所有变量引用都静态绑定到特定变量,所以永远不需要捕获动态数量的字段或类似的东西。要捕获的字段是静态已知的。