我有一个方法调用表达式并尝试调用该方法。我找到了一种方法,但是我在检索参数值方面遇到了问题,因为不是每个参数都用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
检索方法参数值?
或者有更简单的方法来实现我的目标吗?
答案 0 :(得分:26)
您无需担心检索参数并自行调用MethodInfo,您可以让.NET为您执行此操作。您需要做的就是创建一个包含该方法的Lambda表达式。
例如
MethodCallExpression expression = GetExpressionSomeHow();
object result = Expression.Lambda(expression).Compile().DynamicInvoke();
无论如何,这就是我在Linq提供商中处理嵌套查询的方式。
编辑:实际上,看起来你可能已经在选择器变量中有一个LambdaExpression。在这种情况下,您应该能够直接编译并调用它:
object result = selector.Compile().DynamicInvoke();
答案 1 :(得分:7)
编译表达式是一项非常密集的操作,所以如果您计划重新使用表达式,我只会这样做。否则我会推荐反射方式;你会发现它执行得更快。切勿在紧密循环中调用expression.Compile()。
答案 2 :(得分:1)
@ Ch00k&lt; - 谢谢,很好的解释。我只想补充一点
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);
答案 3 :(得分:1)
如果要将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(&#34; mystring&#34;)或func(&#34; my string&#34;);
这里的秘诀是你需要传递你在创建Expression.Call时使用的相同参数,否则你会收到类型&#34; InvalidOperationException&#34;的错误。变量&#39; s&#39;类型&#39; System.String&#39;引用范围&#39;&#39;,但未定义。
答案 4 :(得分:0)
我会尝试这个来返回对象:
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();