DynamicMethods,Expression Trees和DLR

问题描述:

我对DynamicMethods,Expression Trees和DLR之间的交互和关系有一些疑问。DynamicMethods,Expression Trees和DLR

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

    a。 DynamicMethods调用速度更快

    b。编译的LambdaExpressions可以嵌入闭包(ConstantExpressions是非原始值)

    b。编译的LambdaExpressions没有DeclaringType。

    问题:

    a。为什么DynamicMethods比编译的LambdaExpressions更快地调用?

    b。编译的LambdaExpressions允许关闭的特别之处是什么?当我使用非常量表达式时,表达式树实际上是否生成闭包类?如果是这样,这个生成的课程在哪里?

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

  2. 我知道动态关键字实际上只是一个用于发射CSharp CallSites,Binders等的编译器技巧。据我所知,这些生成表达式树并且还使用了C#编译器的精简版本。

    问题

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

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

    c。 C#编译器的精简版本在哪里以及为什么会起作用?为什么以及它与定期调用LambdaExpression.Compile或DynamicMethods或任何类型的IL代有什么不同?我可以理解CallSiteBinder如何用于构建表达式树,但为什么在转换发生后需要C#编译器?一旦它以表达式树(这只是一个API)的形式,C#就完全可以做它。

+1

为什么你认为'DynamicMethod'更快?你基于什么声称? – svick

+1

另外,我想你提出的两个问题并没有真正相关。你可能应该问他们两个不同的问题。 – svick

+0

我认为他们更快的个人经验,并在此引用http://stackoverflow.com/questions/1296683/curiosity-why-does-expression-when-compiled-run-faster-than-a-minimal-dyna(即使标题表明相反),这里http://stackoverflow.com/questions/10673756/net-dynamic-method-best-performance。虽然这个差异很小,我一直认为它只是在发射的IL上略有差异。 – Jeff

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

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

我会很惊讶,如果他们,因为Expression.Compile()内部使用DynamicMethod

编译好的LambdaExpressions允许闭包的特别之处是什么?当我使用非常量表达式时,表达式树实际上是否生成闭包类?如果是这样,这个生成的课程在哪里?

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

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

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

+0

我在编译的lambda表中看到了关于闭包类的一点。这回答了我的问题。谢谢。这也解释了为什么JIT优化能为一个普通DynamicMethod的VS由一个表达式树创建了一个非常不同的效果(这是绑定到一个封闭类的实例) – Jeff

+0

我拆开表达式树的API的closure类多,现在我把它(所有的点号1)。我想最简单的方法来达到我的dlr问题的底部是做更多的反汇编。谢谢。我错过了关于闭包类如何跟踪常量的关键点。 – Jeff

嗯,我无法回答你所有的问题,但我可以回答其中的一些问题,我认为这可能会回答你的大部分问题。也许至少它会给你足够的信息来继续研究。

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

,我不认为是这样,也许你测量错了,这是一个JIT'ing差异

什么特别的编译LambdaExpressions允许倒闭?当我使用非常量表达式时,表达式树实际上是否生成闭包类?如果是这样,这个生成的课程在哪里?

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

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

System.Linq.Expressions真的只是在Reflection.Emit的顶部的友好的API,他们只是存储在内存中,就像Reflection.Emit的ERGO是在默认情况下(尽管Reflection.Emit的保存退出即可发射的代码,我相信)

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

我只是做了一些工作System.Dynamic,所以我不能回答这个问题,但它是我的理解是,CallSiteBinder只是缓存并调用表达,但通过实际发电关闭别的东西(即DynamicObject)。但是,再次,你可能比我更了解更多。

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

不,动态仍受到.net中所有其他规则的约束。 Dynamic只是说“在运行时,当我做x时,去尝试构建我通常会为我编写并执行的代码。”像DynamicObject这样的东西只是要构建一个普通的表达式树,动态对象只是为您提供一些元数据,以便您可以实际构建该树(如返回类型,访问类型,名称等)。

在哪里,为什么C#编译器的精简版开始发挥作用?为什么以及它与定期调用LambdaExpression.Compile或DynamicMethods或任何类型的IL代有什么不同?我可以理解CallSiteBinder如何用于构建表达式树,但为什么在转换发生后需要C#编译器?一旦它以表达式树(这只是一个API)的形式,C#就完全可以做它。

我不知道你的意思是剥离下来的编译器或运行时实际上产生IL代码(我认为这是你在这里后),所以我不认为我可以回答这个。

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

+0

编译器参考的精简版本基于Eric Lippert所做的评论。应该注意到,在我的问题中,对不起。 – Jeff