如何从 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 表达式以获取用于调用的委托。 Action action = selector.Compile(); // 在可枚举的 foreach 中的每个项目上调用表达式(TSource item in source) action(item);最后我还找到了这个问题的 msdn 文档:msdn.microsoft.com/en-us/library/bb882536.aspx 你有什么理由不能只做selector.Compile()()?为什么在括号有效时使用InvokeDynamicInvoke【参考方案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 调用方法的主要内容,如果未能解决你的问题,请参考以下文章

如何从 C# 中的 URL 下载文件?

如何从 c# 中的 aws cognito 获取用户属性

如何从 C# 中的 SQL 查询结果填充类?

如何从 C# 中的文本文件中删除一行?

如何从 C# 中的 Stripe Subscription 对象中检索产品信息?

如何从 C# 中的 C++ dll 中的全局变量从函数中获取返回数组?