Как вызвать метод из выражения MethodCallExpression в c # - PullRequest
20 голосов
/ 22 апреля 2009

У меня есть выражение вызова метода и я пытаюсь вызвать метод. Я нашел способ, но у меня проблемы с получением значений параметров, так как не каждый аргумент описывается с помощью выражения ConstantExp.

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?

Или есть более простой способ достичь моей цели?

Ответы [ 5 ]

26 голосов
/ 22 апреля 2009

Вам не нужно беспокоиться о получении аргументов и вызове MethodInfo самостоятельно, вы можете позволить .NET сделать это за вас. Все, что вам нужно сделать, это создать лямбда-выражение, содержащее этот метод.

например.

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

Так или иначе, я имею дело с вложенными запросами в моем провайдере Linq.

РЕДАКТИРОВАТЬ: На самом деле, похоже, у вас уже может быть LambdaExpression в переменной селектора. В этом случае вы должны иметь возможность просто скомпилировать и вызвать его напрямую:

object result = selector.Compile().DynamicInvoke();
7 голосов
/ 26 сентября 2009

Компиляция выражения является очень интенсивной операцией, поэтому я буду делать это только в том случае, если вы планируете повторно использовать выражение. Я бы порекомендовал способ отражения иначе; Вы найдете, что это выполняется быстрее. Никогда не вызывайте expression.Compile () в узком цикле.

1 голос
/ 24 марта 2017

Если вы хотите скомпилировать ваш 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», переменную «s» типа «System.String», на которую ссылается область действия «, но это не определено.

1 голос
/ 17 августа 2010

@ Ch00k <- Спасибо, хорошее объяснение. Я просто хотел бы добавить, что </p>

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);
0 голосов
/ 18 февраля 2015

Я бы попробовал это вернуть объект:

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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...