如何从c#中的MethodCallExpression调用该方法

我有一个方法调用表达式并尝试调用该方法。 我找到了一种方法,但是我在检索参数值方面遇到了问题,因为不是每个参数都用ConstantExpression描述。

Expression<Action> = 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() .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检索方法参数值?

或者有更简单的方法来实现我的目标吗?

您不必担心检索参数并自己调用MethodInfo,您可以让.NET为您执行此操作。 您需要做的就是创建一个包含该方法的Lambda表达式。

例如。

 MethodCallExpression expression = GetExpressionSomeHow(); object result = Expression.Lambda(expression).Compile().DynamicInvoke(); 

这就是我在Linq提供程序中处理嵌套查询的方法。

编辑:实际上,看起来你可能已经在选择器变量中有一个LambdaExpression。 在这种情况下,您应该能够直接编译并调用它:

 object result = selector.Compile().DynamicInvoke(); 

编译表达式是一个非常密集的操作,所以如果你打算重新使用表达式,我只会这样做。 否则我会推荐reflection方式; 你会发现它执行得更快。 永远不要在紧密循环中调用expression.Compile()。

@ 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> 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); 

如果要将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>(call, call.Arguments.OfType()); var func = lambda.Compile(); int result = func("sample string input"); 

这允许你简单地执行func.Invoke(“mystring”)或func(“my string”);

这里的秘诀是你需要传递你在创建Expression.Call时使用的相同参数,否则你会得到类型为“System.String”的类型为“InvalidOperationException”的变量”的错误,但是它是没有定义的。

我会尝试这个返回对象:

 private static object _getValue(MethodCallExpression expression) { var objectMember = Expression.Convert(expression, typeof(object)); var getterLambda = Expression.Lambda>(objectMember); var getter = getterLambda.Compile(); return getter(); } 

可以更快地调用以下内容:

 LambdaExpression l = Expression.Lambda(Expression.Convert(element, element.Type)); return l.Compile().DynamicInvoke();