Creating an expression tree that calls a method

Is it possible to create an expression tree that directly calls a method? For example, consider the following method:

public static int MyFunc(int a, int b) { return a + b; } 

I would like to create an expression tree that calls MyFunc with parameters a = 1 and b = 2. One way to achieve this is with reflection:

 var c1 = Expression.Constant(1); var c2 = Expression.Constant(2); var expr = Expression.Call(typeof(Program).GetMethod("MyFunc"), c1, c2); 

However, this is disadvantageous because reflection is slow and turns what should be errors during compilation at runtime.

Instead, I could use the following approach:

 Expression<Func<int, int, int>> lambda = (a, b) => MyFunc(a, b); var expr = Expression.Invoke(lambda, c1, c2); 

But this is still not what I want, because it wraps the method in a lambda expression instead of a direct call.

A good solution might be based on a delegate, for example:

 Func<int, int, int> del = Program.MyFunc; var expr = Expression.Invoke(del, c1, c2); 

Unfortunately, this does not compile because del is a delegate, not an expression. Is there a way to build an expression from a delegate? (Note that I know the purpose of the delegate at compile time, so I don't need the flexibility described here: Expression trees and calling a delegate .)

A non-delegate solution would also be great if it calls the target method as direct as possible.

Update: This also works, but it still depends on reflection:

 Func<int, int, int> del = Program.MyFunc; var expr = Expression.Call(del.Method, c1, c2); 

At least more likely to catch problems at compile time. But he still pays the price of time per view, right?

+7
reflection c # lambda delegates expression-trees
source share
1 answer

As long as you call .Compile on the lambda and save (and reuse) the delegate, you only pay the reflection price once.

 var c1 = Expression.Constant(1); var c2 = Expression.Constant(2); var expr = Expression.Call(typeof(Program).GetMethod("MyFunc"), c1, c2); Func<int> func = Expression.Lambda<Func<int>>(expr).Compile(); // ** now store func and re-use it ** 

However, to get the bare delegate only , this method can be used:

 var method = typeof(Program).GetMethod("MyFunc"); Func<int, int, int> func = (Func<int, int, int>) Delegate.CreateDelegate( typeof(Func<int, int, int>), method); 

Of course, then you are forced to provide constants for the caller.

Another option is DynamicMethod , but as long as you cache the last delegate, it will not be much faster. It offers more flexibility (at the price of complexity), but that doesn't seem to be a problem.

+11
source share

All Articles