Reputation: 52240
I am writing a method intended to parse a method call expression and determine (1) the method being called and (2) the arguments being passed. I can retrieve the method just fine but am having trouble evaluating the argument expressions.
Here is the code:
public static void InspectExpression(Expression<Action<Input>> expression)
{
var memberExpression = expression.Body as MethodCallExpression;
var methodName = memberExpression.Method.Name;
Console.WriteLine("The expression calls the {0} method.", methodName);
var argumentExpression = memberExpression.Arguments[0];
var argumentLambda = Expression.Lambda<Func<string>>(argumentExpression);
var compiled = argumentLambda.Compile();
var argumentValue = compiled();
Console.WriteLine("The expression would pass {0} as the first argument to {1}", argumentValue, methodName);
}
I am calling it with the following code:
public class Input
{
public string SomeProperty { get; set; }
}
public static void MethodName(string arg)
{
//Doesn't matter what this does
}
public static void Main()
{
InspectExpression( i => MethodName(i.SomeProperty) );
}
However this yields the following exception:
[System.InvalidOperationException: variable 'i' of type 'Input' referenced from scope '', but it is not defined]
This makes sense since there is no way to evaluate that expression without knowing the value of the input, since the argument is computed based on the expression's input.
So I tried adding the input like this:
public static void InspectExpression(Expression<Action<Input>> expression)
{
var memberExpression = expression.Body as MethodCallExpression;
var methodName = memberExpression.Method.Name;
Console.WriteLine("The expression calls the {0} method.", methodName);
var argumentExpression = memberExpression.Arguments[0];
var argumentLambda = Expression.Lambda<Func<Input,string>>(argumentExpression);
var compiled = argumentLambda.Compile();
var sampleInput = new Input { SomeProperty = "Hello world" };
var argumentValue = compiled(sampleInput);
Console.WriteLine("The expression would pass {0} as the first argument to {1}", argumentValue, methodName);
}
This raised the exception:
[System.ArgumentException: Incorrect number of parameters supplied for lambda declaration]
I'm guessing I have to add a parameter reference to the expression somehow, but I'm at a loss exactly how to do this.
Give a sample input, how can I retrieve the computed argument to this expression?
Here is a link to a Fiddle in case you'd like to try it out or use it as the basis of an example solution.
Upvotes: 0
Views: 251
Reputation: 23721
You'll need to pass a set of parameters to the Expression.Lambda<...>()
call - you should be able to use the same set of parameters as the original expression
, so change your definition of argumentLambda
to:
var argumentLambda = Expression.Lambda<Func<Input,string>>(argumentExpression, expression.Parameters);
Upvotes: 1