簡體   English   中英

如何從c#中的MethodCallExpression調用該方法

[英]How to call the method from a MethodCallExpression in c#

我有一個方法調用表達式並嘗試調用該方法。 我找到了一種方法,但是我在檢索參數值方面遇到了問題,因為不是每個參數都用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檢索方法參數值?

或者有更簡單的方法來實現我的目標嗎?

您不必擔心檢索參數並自己調用MethodInfo,您可以讓.NET為您執行此操作。 您需要做的就是創建一個包含該方法的Lambda表達式。

例如。

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

這就是我在Linq提供程序中處理嵌套查詢的方法。

編輯:實際上,看起來你可能已經在選擇器變量中有一個LambdaExpression。 在這種情況下,您應該能夠直接編譯並調用它:

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

編譯表達式是一個非常密集的操作,所以如果您計划重新使用表達式,我只會這樣做。 否則我會推薦反射方式; 你會發現它執行得更快。 永遠不要在緊密循環中調用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<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);

如果要將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時使用的相同參數,否則你會得到類型為“System.String”的類型為“InvalidOperationException”的變量''的錯誤,但是它是沒有定義的。

我會嘗試這個返回對象:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM