5

我对 DynamicMethods、表达式树和 DLR 之间的交互和关系有一些疑问。

  1. 我知道 LambdaExpression.Compile 在内部使用 ILGenerator 来创建委托。但是,编译的 LambdaExpression 和 DynamicMethod 之间存在一些根本区别。例如

    一个。DynamicMethods 调用更快

    湾。编译的 LambdaExpressions 可以嵌入闭包(非原始值的常量表达式)

    湾。编译的 LambdaExpressions 没有 DeclaringType。

    问题:

    一个。为什么调用 DynamicMethods 比调用已编译的 LambdaExpressions 更快?

    湾。允许闭包的编译 LambdaExpressions 有什么特别之处?当我使用非 ConstantExpression 时,表达式树是否真的生成了一个闭包类?如果是这样,这个生成的类会去哪里?

    C。编译的 LambdaExpressions 去哪里(在运行时)?对他们的支持在哪里实施。它不能只是 Reflection.Emit,可以吗?

  2. 我知道 dynamic 关键字实际上只是用于发出 CSharp CallSites、Binders 等的编译器技巧。据我了解,在内部,它们会生成表达式树,并且还使用 C# 编译器的精简版本。

    问题

    一个。生成的表达式树是一般 CallSiteBinders 的函数还是它们在 Microsoft.CSharp dll 中的具体实现和使用?

    湾。这些表达式树是由 DynamicExpression 节点组成的吗?或者是其他东西?如果是别的,为什么?

    C。C# 编译器的精简版在哪里以及为什么会发挥作用?为什么以及它与对 LambdaExpression.Compile 或 DynamicMethods 或任何类型的 IL 生成的常规调用有何不同?我可以理解如何使用 CallSiteBinders 来构建表达式树,但为什么在转换发生后需要 C# 编译器?一旦它采用表达式树(这只是一个 API)的形式,C# 与它有什么关系。

4

2 回答 2

4

我对 的了解不多dynamic,所以我只回答你问题的第一部分。

为什么调用 DynamicMethods 比调用已编译的 LambdaExpressions 更快?

如果他们是,我会感到非常惊讶,因为Expression.Compile()内部使用DynamicMethod.

允许闭包的编译 LambdaExpressions 有什么特别之处?当我使用非 ConstantExpression 时,表达式树是否真的生成了一个闭包类?如果是这样,这个生成的类会去哪里?

这很容易验证。只需查看编译表达式树生成的委托TargetMethod您会注意到Target(和第一个参数Method)是System.Runtime.CompilerServices.Closure。这是一个包含 field 的类,其中存储了来自 s 的object[] Constants非原始值。ConstantExpression

编译的 LambdaExpressions 去哪里(在运行时)?对他们的支持在哪里实施。它不能只是 Reflection.Emit,可以吗?

就像我之前说的,Expression.Compile()内部使用DynamicMethod. 所以,是的,它只是 Reflection.Emit。

于 2013-07-23T17:39:39.293 回答
2

好吧,我不能回答你所有的问题,但我可以回答其中的几个,我想这可能会回答你的大部分问题。也许至少它会给你足够的信息来继续研究。

为什么调用 DynamicMethods 比调用已编译的 LambdaExpressions 更快?

我不认为他们是,也许你测量错了,这是 JIT 的差异

允许闭包的编译 LambdaExpressions 有什么特别之处?当我使用非 ConstantExpression 时,表达式树是否真的生成了一个闭包类?如果是这样,这个生成的类会去哪里?

这个我不确定。我会假设 Expression.Constant 可以包含引用类型,那么这不是问题,但是如果它确实只能具有值类型,那么我猜编译器只会生成一个表达式,其中变量在闭包中被捕获只是作为参数传入。

编译的 LambdaExpressions 去哪里(在运行时)?对他们的支持在哪里实施。它不能只是 Reflection.Emit,可以吗?

System.Linq.Expressions实际上只是 Reflection.Emit 之上的一个更友好的 API,因此它们只是存储在内存中,就像默认情况下 Reflection.Emit 一样(尽管我相信使用 Reflection.Emit 你可以保存发出的代码)

生成的表达式树是一般 CallSiteBinders 的函数还是它们在 Microsoft.CSharp dll 中的具体实现和使用?

我只做了一点 System.Dynamic 工作,所以我无法回答这个问题,但我的理解是 CallSiteBinder 只是缓存并调用表达式,但将实际生成传递给其他东西(即 DynamicObject)。但同样,你在这里可能比我知道的更多。

这些表达式树是由 DynamicExpression 节点组成的吗?或者是其他东西?如果是别的,为什么?

不,动态仍然受与 .net 中其他所有内容相同的规则约束。动态只是说“在运行时,当我执行 x 时,去尝试构建我通常编写的代码并为我执行它。” 诸如构建一个普通的旧表达式树之类的事情DynamicObject,动态对象只是为您提供一些元数据,以便您实际上可以构建该树(如返回类型、访问类型、名称等)。

C# 编译器的精简版在哪里以及为什么会发挥作用?为什么以及它与对 LambdaExpression.Compile 或 DynamicMethods 或任何类型的 IL 生成的常规调用有何不同?我可以理解如何使用 CallSiteBinders 来构建表达式树,但为什么在转换发生后需要 C# 编译器?一旦它采用表达式树(这只是一个 API)的形式,C# 与它有什么关系。

我不确定您所说的精简编译器是什么意思,或者运行时实际上为生成 IL 代码做了什么(我认为这是您在这里所追求的),所以我认为我无法回答这个问题。

然而,我会说,就像我之前说的:这些System.Linq.Expression东西实际上只是在 Reflection.Emit 之上的一个友好的 API。表达式树只是它需要的信息去反射.emit,生成一个动态方法,然后返回给你。

于 2013-07-23T17:29:06.610 回答