我对DynamicMethods,Expression Trees和DLR之间的交互和关系有一些疑问。
我知道LambdaExpression.Compile在内部使用ILGenerator来创建一个Delegate。但是,编译的LambdaExpression和DynamicMethod之间存在一些根本区别。例如
一个。
更快地调用DynamicMethods湾编译的LambdaExpressions可以嵌入闭包(ConstantExpressions是非原始值)
湾编译的LambdaExpressions没有DeclaringType。
问题:
一个。为什么DynamicMethods比编译的LambdaExpressions更快地调用?
湾有关允许闭包的已编译LambdaExpressions有什么特别之处?当我使用非ConstantExpression时,表达式树是否实际生成了闭包类?如果是这样,这个生成的课程去哪了?
℃。编译的LambdaExpressions在哪里(在运行时)?在哪里实施了对它们的支持。它不能只是Reflection.Emit,可以吗?
我知道动态关键字实际上只是用于发出CSharp CallSites,Binders等的编译器技巧。据我所知,在内部生成表达式树,并且还使用了C#编译器的精简版本。 / p>
问题
一个。生成的表达式树是否一般是CallSiteBinders的函数,还是Microsoft.CSharp dll中它们的具体实现和用法?
湾这些表达式树是否由DynamicExpression节点组成?或者是其他东西?如果有别的,为什么?
℃。 C#编译器的精简版本在何处以及为何发挥作用?为什么以及如何与常规调用LambdaExpression.Compile或DynamicMethods或任何类型的IL生成不同?我可以理解CallSiteBinders如何用于构建表达式树,但为什么在转换发生后需要C#编译器呢?一旦它以表达式树(它只是一个API)的形式存在,C#与它有什么关系。
答案 0 :(得分:3)
我对dynamic
了解不多,所以我只回答你问题的第一部分。
为什么DynamicMethods比编译的LambdaExpressions更快地调用?
如果他们是,我会非常惊讶,因为Expression.Compile()
内部使用DynamicMethod
。
允许关闭的已编译LambdaExpressions有什么特别之处?当我使用非ConstantExpression时,表达式树是否实际生成了闭包类?如果是这样,这个生成的课程去哪了?
这很容易验证。只需查看通过编译表达式树生成的委托的Target
和Method
。您会注意到Target
(Method
的第一个参数)是System.Runtime.CompilerServices.Closure
。这是一个包含字段object[] Constants
的类,它存储来自ConstantExpression
的非原始值。
编译的LambdaExpressions在哪里(在运行时)?在哪里实施了对它们的支持。它不能只是Reflection.Emit,可以吗?
就像我之前说的那样,Expression.Compile()
内部使用DynamicMethod
。所以,是的,它只是Reflection.Emit。
答案 1 :(得分: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
之类的东西只是构建一个普通的旧表达式树,动态对象只是为你提供一些元数据,这样你实际上可以构建那个树(如返回类型,访问类型,名称等)。 / p>
C#编译器的精简版在哪里以及为什么发挥作用?为什么以及如何与常规调用LambdaExpression.Compile或DynamicMethods或任何类型的IL生成不同?我可以理解CallSiteBinders如何用于构建表达式树,但为什么在转换发生后需要C#编译器呢?一旦它以表达式树(它只是一个API)的形式存在,C#与它有什么关系。
我不确定你是什么意思被剥离的编译器或运行时实际上做什么来生成IL代码(我认为这是你在这里之后),所以我认为我不能回答这个问题。
然而,我会说,就像我之前说过的那样:System.Linq.Expression
内容实际上只是一个友好的API,位于Reflection.Emit之上。表达式树只是它需要进入reflection.emit,生成动态方法并将其返回给您的信息。