如何从 C# 中的 MethodCallExpression 调用方法
Posted
技术标签:
【中文标题】如何从 C# 中的 MethodCallExpression 调用方法【英文标题】:How to call the method from a MethodCallExpression in c# 【发布时间】:2010-10-21 01:24:22 【问题描述】:我有一个方法调用表达式并尝试调用该方法。我想出了一个办法,但我在检索参数值时遇到了问题,因为不是每个参数都用 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);
此外,我还看到了一些其他调用该方法的方法,现在我不确定什么是正确的方法。
var func = expression.Compile();
var success = func.Invoke();
所以我的问题是,如何从methodCallExpression.Arguments
检索方法参数值?
或者有没有更简单的方法来实现我的目标?
【问题讨论】:
【参考方案1】:您无需担心自己检索参数和调用 MethodInfo,您可以让 .NET 为您完成。您需要做的就是创建一个包含该方法的 Lambda 表达式。
例如。
MethodCallExpression expression = GetExpressionSomeHow();
object result = Expression.Lambda(expression).Compile().DynamicInvoke();
这就是我在我的 Linq 提供程序中处理嵌套查询的方式。
编辑:实际上,看起来您可能已经在选择器变量中有一个 LambdaExpression。在这种情况下,您应该能够直接编译和调用它:
object result = selector.Compile().DynamicInvoke();
【讨论】:
谢谢,这样容易多了。我现在这样做:// 编译 lambda 表达式以获取用于调用的委托。 Actionselector.Compile()()
?为什么在括号有效时使用Invoke
或DynamicInvoke
?【参考方案2】:
编译表达式是一项非常密集的操作,因此只有在您计划重新使用该表达式时,我才会这样做。否则我会推荐反射方式;你会发现它执行得更快。切勿在紧密循环中调用 expression.Compile()。
【讨论】:
【参考方案3】:@Ch00k
selector.Compile();
给你一个委托。对于实例方法,您需要一个实例来调用此方法。您将此实例作为参数传递给 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);
【讨论】:
【参考方案4】:如果您想将您的 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");
这使您可以简单地执行 func.Invoke("mystring") 或 func("my string");
这里的秘密是你需要传递你在创建 Expression.Call 时使用的相同参数,否则你会得到一个类型为“InvalidOperationException”的错误,类型为“System.String”的变量 's' 从范围''引用,但它没有定义。
【讨论】:
【参考方案5】:我会尝试这个来返回对象:
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();
调用以下命令会快很多:
LambdaExpression l = Expression.Lambda(Expression.Convert(element, element.Type));
return l.Compile().DynamicInvoke();
【讨论】:
以上是关于如何从 C# 中的 MethodCallExpression 调用方法的主要内容,如果未能解决你的问题,请参考以下文章