Error in expression tree: System.InvalidOperationException: variable 'message' of type 'A' referenced from scope '', but it is not defined

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.

Jon Skeet
people
quotationmark

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.

people

See more on this question at Stackoverflow