2016-09-27 2 views
-1

У меня есть следующая функция, в которой я хочу, чтобы пройти через параметры функции ...Преобразование вызова функции в выражении C#

private static void TestExpression(Expression expr) 
    {    
     MethodCallExpression methodCall = expr as MethodCallExpression; 
     if(methodCall == null) 
      throw new ArgumentException("not a function call"); 

     ReadOnlyCollection<Expression> args = methodCall.Arguments; 
     ParameterInfo[] param = methodCall.Method.GetParameters(); 
     param.ToList().ForEach(p => Console.WriteLine(p.Name)); 
    } 

Только для иллюстративного У меня также есть фиктивная функция ...

static int SomeFunc(int a, int b) 
    { 
     return 0; 
    } 

проблема заключается в том, что я не знаю, как преобразовать вызов функции в выражение, то есть, я не знаю, как сделать следующий вызов

TestExpression(/*Something here converting SomeFunc(20, 30) to a Expression*/) 

Я хочу упомянуть, что мне не нужны другие методы для прохождения параметров. Я пробовал несколько вариантов с лямбда-выражениями, но без успеха ...

+0

Я забыл упомянуть, что используется .Net 3.5 – user2436426

ответ

2

Чтобы заставить его работать с вашей текущей реализацией, вам нужно явно создать выражение и извлечь из него тело. Код будет выглядеть так:

TestExpression(((Expression<Func<int>>)(() => SomeFunc(1, 2))).Body); 

но это не очень читаемо.

EDIT: Для получения большей удобочитаемости потребуется дополнительная информация, например, конкретный прецедент.

EDIT: Для получения дополнительной читаемости, вы могли бы использовать что-то вроде этого:

private static void TestExpression<T>(Expression<Func<T>> expr) 
{ 
    TestExpression(expr.Body); 
} 

Это позволит вам вызвать метод как это:

TestExpression(() => SomeFunc(1, 2)); 

Конечно, вам все равно нужно укажите значения по умолчанию для аргументов. Чтобы преодолеть это, вам нужно слегка изменить TestExpression перегрузку, но в большинстве случаев вывод типа не будет работать. Вы можете изучить это самостоятельно, если хотите.

+0

Я уже пробовал эту версию, но в конечном итоге это вызовет исключение ArgumentException, а это значит, что это недействительное выражение MethodCallExpression. Случай использования состоит в том, что я хочу сделать тестовую функцию (для модульных тестов), которая принимает функцию (или делегат), проходит через ее параметры и тесты, которые бросают ArgumentNullException, если они являются нулевыми. Это автоматизация, чтобы избежать громоздких и повторяющихся тестов. Я нашел несколько примеров в сети, но они были неполными или они не работали. Кроме того, я злюсь, что не могу сделать это с помощью этого метода и хочу знать, как это сделать. – user2436426

+0

Я тестировал это локально. Вы видите '.Body' в конце цепочки? В самом деле, без него это не сработает, потому что тогда тип выражения будет выражаться «Expression >», который происходит из 'LambdaExpression', следовательно' .Body' для извлечения фактического выражения. Для вашего случая я бы представил еще один уровень вызовов методов, чтобы сделать его более читаемым. См. Мой ответ, отредактированный. – kiziu

+0

Спасибо, пригвоздил его. В первом тесте вашего решения я забыл прокомментировать мою версию вызова TestExpression, которая была скрыта среди многих комментариев. Таким образом, я фактически получал ArgumentException из моей версии. Не вижу леса для комментариев .... Еще раз спасибо. – user2436426

Смежные вопросы