I have some questions about the interactions and relationships between DynamicMethods, Expression Trees and the DLR.
I know that LambdaExpression.Compile uses an ILGenerator internally to create a Delegate. However, there are some fundamental differences between a compiled LambdaExpression and a DynamicMethod. For instance
a. DynamicMethods invoke faster
b. Compiled LambdaExpressions can embed closures (ConstantExpressions that are non primitive values)
b. Compiled LambdaExpressions have no DeclaringType.
Questions:
a. Why are DynamicMethods faster to invoke than compiled LambdaExpressions?
b. What's special about compiled LambdaExpressions that allows for closures? Does the Expression Tree actually generate a closure class when I use a non ConstantExpression? And if so, where does this generated class go?
c. Where do compiled LambdaExpressions go (at runtime)? Where is the support for them implemented. It can't just be Reflection.Emit, can it?
I know that the dynamic keyword is really just a compiler trick for emitting CSharp CallSites, Binders, etc. Internally, as I understand, these generate Expression Trees and also use a stripped down version of the C# compiler.
Questions
a. Are the expression trees being generated a function of CallSiteBinders in general or the specific implementation and usage of them in the Microsoft.CSharp dll?
b. Are these expression trees composed of DynamicExpression nodes? Or something else? If something else, why?
c. Where and why does the stripped down version of the C# compiler come into play? Why and how is it different than regular calls to LambdaExpression.Compile or DynamicMethods or any kind of IL generation? I can understand how CallSiteBinders could be used to build Expression Trees, but why is the C# compiler needed after that transformation occurs? And what does C# have to do with it at all once it's in the form of an Expression Tree (which is just an API).
I don't know much about dynamic
, so I'm going to answer only the first part of your question.
Why are DynamicMethods faster to invoke than compiled LambdaExpressions?
I would be very surprised if they were, since Expression.Compile()
internally uses DynamicMethod
.
What's special about compiled LambdaExpressions that allows for closures? Does the Expression Tree actually generate a closure class when I use a non ConstantExpression? And if so, where does this generated class go?
That's easy to verify. Just look at Target
and Method
of a delegate generated from compiling an expression tree. You will notice that the Target
(and first parameter of Method
) is System.Runtime.CompilerServices.Closure
. That's a class that contains a field object[] Constants
, which is where non-primitive values from ConstantExpression
s are stored.
Where do compiled LambdaExpressions go (at runtime)? Where is the support for them implemented. It can't just be Reflection.Emit, can it?
Like I said before, Expression.Compile()
internally uses DynamicMethod
. So, yeah, it is just Reflection.Emit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With