I need to build Action
which will represent this code:
(new P()).Handle(argument type of A)
I have an expression for this:
Expression.Lambda<Action<A>>(Expression.Call(Expression.New(typeof(P)),
typeof(P).GetMethod("Handle",
BindingFlags.Instance | BindingFlags.Public),
Expression.Parameter(typeof(A),
"message")),
Expression.Parameter(typeof(A), "message"))
.Compile();
But it's throw an error when I'm trying to compile it. Error is:
System.TypeInitializationException: The type initializer for 'PerformanceBenchma rk.Test' threw an exception. ---> System.InvalidOperationException: variable 'message' of type 'PerformanceBenchmark.A' referenced from scope '', but it is not defined
My code looks like this:
public class A
{
}
public interface IInt<T>
{
void Handle(T item);
}
public class P : IInt<A>
{
public void Handle(A item)
{
return;
}
}
public class Test
{
public static readonly Action<A> _expr = Expression.Lambda<Action<A>>(Expression.Call(Expression.New(typeof(P)), typeof(P).GetMethod("Handle", BindingFlags.Instance | BindingFlags.Public), Expression.Parameter(typeof(A), "message")), Expression.Parameter(typeof(A), "message")).Compile();
}
my goal is to measure how fast _expr(new A())
will be calling. But now it's fails on expression compilation.
The problem is that you're calling Expression.Parameter
twice, so you've got two different parameter expressions. They don't bind by name, unfortunately.
So the solution is simply to use multiple statements, creating a ParameterExpression
once and then using it twice. The code is much easier to read that way too:
var method = typeof(P).GetMethod("Handle", BindingFlags.Instance | BindingFlags.Public);
var parameter = Expression.Parameter(typeof(A), "message");
var ctorCall = Expression.New(typeof(P));
var methodCall = Expression.Call(ctorCall, method, parameter);
var expressionTree = Expression.Lambda<Action<A>>(methodCall, parameter);
var compiled = expressionTree.Compile();
Of course to initialize a static field with that code, you'll either need to put it in a helper method or in a static constructor.
See more on this question at Stackoverflow