I have a method call expression and try to invoke the method. I figured out a way, but I have problems in retrieving the parameter values since not every argument is described with a ConstantExpression.
Expression<Action<T>> = t => t.DoSomething(Par0, Par1, Par2);
MethodCallExpression methodCallExpression = selector.Body
as MethodCallExpression;
// get the information which is needed to invoke the method from the provided
// lambda expression.
MethodInfo methodInfo = methodCallExpression.Method;
object[] arguments = methodCallExpression.Arguments.OfType<ConstantExpression>()
.Select(p => p.Value).ToArray();
// invoke the expression on every item within the enumerable
foreach (TSource item in source)
{
methodInfo.Invoke(item, arguments);
}
Additionally, I have seen some other ways to invoke the method, now I'm not sure what is the right way to do it.
var func = expression.Compile();
var success = func.Invoke();
So my question is, how can I retrieve the method argument values from methodCallExpression.Arguments
?
Or is there an easier way to achieve my goal?
@Ch00k <-- Thanks, nice explanation. I would just like to add that
gives you a delegate. For an instance method you need an instance on which to call this method. You pass this instance as the argument to DynamicInvoke ala
You don't need to worry about retrieving the arguments and calling the MethodInfo yourself, you can let .NET do it for you. All you need to do is create a Lambda expression containing that method.
eg.
That's how I deal with nested queries in my Linq provider anyway.
EDIT: Actually, it looks like you might already have a LambdaExpression in the selector variable. In that case, you should be able to just compile and invoke it directly:
If you want to compile your expression.call into a Action or Func, this is how you do:
This allows you to simply do func.Invoke("mystring") or func("my string");
The secret here is you need to pass the same parameters you used when creating the Expression.Call, otherwise you get an error of type "InvalidOperationException" variable 's' of type 'System.String' referenced from scope '', but it is not defined.
Compiling an expression is a very intensive operation, so I would only do that if you are planning on re-using the expression. I would recommend the reflection way otherwise; you will find it executes faster. Never call expression.Compile() in a tight loop.
I would try this to return the object:
It is much faster can calling the following: