Search code examples
c#lambdaexpression-trees

How to compile MethodCallExpression with operations on arguments?


I have a method Method

private static int Method(int n)
{
    return n;
}

I get MethodCallExpression in overrided VisitMethodCall in my ExpressionVisitor. MethodCallExpression contains:

n => Method(2 + n)

I want to compile it to Func and call like this:

func(3)

And it's should return 5.

I tried this:

    IEnumerable<ParameterExpression> parameters = expression.Arguments.Select(a => Expression.Parameter(a.Type, a.ToString()));
    MethodCallExpression call = Expression.Call(expression.Method, parameters);
    Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, call.Arguments.OfType<ParameterExpression>());
    var func = lambda.Compile();
    Console.WriteLine(func(3));

And it's return me 3, not 5

It is because 2+x it is param name and I replace it with 3.


Solution

  • Not sure why you would ever do this, but anyway to do this you need to extract parameters (not arguments) used by your MethodCallExpression. For that you can abuse expression visitor like this:

    public class ParametersExtractorVisitor : ExpressionVisitor {
        public IList<ParameterExpression> ExtractedParameters { get; } = new List<ParameterExpression>();
        protected override Expression VisitParameter(ParameterExpression node) {
            ExtractedParameters.Add(node);
            return base.VisitParameter(node);
        }
    }
    

    Then use it like this in your code:

    var visitor = new ParametersExtractorVisitor();
    visitor.Visit(expression);
    MethodCallExpression call = Expression.Call(expression.Method, expression.Arguments);
    Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, visitor.ExtractedParameters);
    var func = lambda.Compile();
    Console.WriteLine(func(3));