如何从c#中的MethodCallExpression调用方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/776442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call the method from a MethodCallExpression in c#
提问by Enyra
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.
我有一个方法调用表达式并尝试调用该方法。我想出了一个方法,但是我在检索参数值时遇到了问题,因为并不是每个参数都用 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
?
所以我的问题是,如何从中检索方法参数值methodCallExpression.Arguments
?
Or is there an easier way to achieve my goal?
或者有没有更简单的方法来实现我的目标?
采纳答案by David Wengier
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.
您无需担心检索参数和自己调用 MethodInfo,您可以让 .NET 为您完成。您需要做的就是创建一个包含该方法的 Lambda 表达式。
eg.
例如。
MethodCallExpression expression = GetExpressionSomeHow();
object result = Expression.Lambda(expression).Compile().DynamicInvoke();
That's how I deal with nested queries in my Linq provider anyway.
无论如何,这就是我在 Linq 提供程序中处理嵌套查询的方式。
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:
编辑:实际上,您可能已经在选择器变量中有一个 LambdaExpression。在这种情况下,您应该能够直接编译和调用它:
object result = selector.Compile().DynamicInvoke();
回答by user179338
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.
编译表达式是一项非常繁重的操作,所以我只会在您计划重新使用该表达式时才这样做。否则我会推荐反射方式;你会发现它执行得更快。切勿在紧密循环中调用 expression.Compile()。
回答by satnhak
@Ch00k <-- Thanks, nice explanation. I would just like to add that
@Ch00k <-- 谢谢,很好的解释。我只想补充一点
selector.Compile();
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
给你一个代表。对于实例方法,您需要一个实例来调用此方法。您将此实例作为参数传递给 DynamicInvoke ala
// Grab the method from MyClass - param1 and param2 are the actual parameters you
// want to pass to the method call.
Expression<Func<MyClass, TValue>> selector = (x => x.MyMethod(param1, param2));
// Create an instance of MyClass to call the method on
var myClass = new MyClass();
// Call the method on myClass through DynamicInvoke
object returnValue = selector.Compile().DynamicInvoke(myClass);
回答by TheMiddleMan
I would try this to return the object:
我会尝试这样返回对象:
private static object _getValue(MethodCallExpression expression)
{
var objectMember = Expression.Convert(expression, typeof(object));
var getterLambda = Expression.Lambda<Func<object>>(objectMember);
var getter = getterLambda.Compile();
return getter();
}
It is much faster can calling the following:
可以更快地调用以下内容:
LambdaExpression l = Expression.Lambda(Expression.Convert(element, element.Type));
return l.Compile().DynamicInvoke();
回答by Rafael Diego Nicoletti
If you want to compile your expression.call into a Action or Func, this is how you do:
如果你想将你的 expression.call 编译成一个 Action 或 Func,你可以这样做:
var method = typeof(MyType).GetMethod(nameof(MyType.MyMethod), BindingFlags.Public | BindingFlags.Static);
var parameter = Expression.Parameter(typeof(string), "s");
var call = Expression.Call(method, parameter);
var lambda = Expression.Lambda<Func<string, int>>(call, call.Arguments.OfType<ParameterExpression>());
var func = lambda.Compile();
int result = func("sample string input");
This allows you to simply do func.Invoke("mystring") or func("my string");
这允许您简单地执行 func.Invoke("mystring") 或 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.
这里的秘密是你需要传递你在创建 Expression.Call 时使用的相同参数,否则你会得到一个类型为“InvalidOperationException”的错误,类型为“System.String”的变量“s”从范围“引用”,但它是没有定义的。