Параметр лямбда-прохода .NET - PullRequest
4 голосов
/ 31 мая 2010

Я надеюсь, что мне не хватает чего-то очевидного, но у меня возникают некоторые проблемы с определением метода, который принимает параметр метода для получения информации о методе для переданного метода. Я НЕ хочу на самом деле выполнить метод.

Я хочу иметь возможность:

  busObject.SetResolverMethod<ISomeInterface>(x=>x.GetNameById);

Где GetNameById - это метод, определенный в интерфейсе ISomeInterface. В этом случае пример метода, передаваемого в подписи, будет:

 MyVarA GetNameById(int id){ .... }

В приведенном выше примере тело SetResolverMethod должно иметь возможность возвращать / хранить строку «GetNameById».

Нет стандартной подписи, которой будет соответствовать передаваемый метод (за исключением того, что он всегда будет возвращать какой-либо объект).

В настоящее время я устанавливаю метод в виде строки (т. Е. "GetNameById"), но я хочу, чтобы он проверялся во время компиляции, поэтому возникает вопрос.

Ответы [ 2 ]

2 голосов
/ 31 мая 2010

Это не особенно красиво / свободно, но если вы действительно хотите избежать передачи фиктивных значений параметров, вы можете использовать выражение, которое возвращает делегат.

SetResolverMethod<ISomeInterface>(x => new Func<int, MyVarA>(x.GetNameById));

Реализация SetResolverMethod будет выглядеть примерно так:

public void SetResolverMethod<T>(Expression<Func<T, Delegate>> expr)
{
    var unary = (UnaryExpression) expr.Body;
    var methodCall = (MethodCallExpression) unary.Operand;
    var constant = (ConstantExpression) methodCall.Arguments[2];
    var method = (MethodInfo) constant.Value;
    Console.WriteLine(method.Name);
}

Редактировать: Если вы хотите создать набор перегрузок для каждого Func<> делегата, вы можете улучшить беглость, включив типы параметров метода в общие типы параметров вашего метода.

p.SetResolverMethod<ISomeInterface, int, MyVarA>(x => x.GetNameById);

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

Я реализовал три перегрузки для параметров 0, 1 и 2:

public void SetResolverMethod<T, TResult>(Expression<Func<T, Func<TResult>>> expr)
{
    SetResolverMethod((LambdaExpression) expr);
}

public void SetResolverMethod<T, T1, TResult>(Expression<Func<T, Func<T1, TResult>>> expr)
{
    SetResolverMethod((LambdaExpression) expr);
}

public void SetResolverMethod<T, T1, T2, TResult>(Expression<Func<T, Func<T1, T2, TResult>>> expr)
{
    SetResolverMethod((LambdaExpression) expr);
}

private void SetResolverMethod(LambdaExpression expr)
{
    var unary = (UnaryExpression) expr.Body;
    var methodCall = (MethodCallExpression) unary.Operand;
    var constant = (ConstantExpression) methodCall.Arguments[2];
    var method = (MethodInfo) constant.Value;
    Console.WriteLine(method.Name);
}
2 голосов
/ 31 мая 2010

Нет способа передать только сам метод. Вы можете сделать это, обернув метод в делегате, но для этого вы должны либо с помощью метода SetResolverMethod определить тип этого делегата (что вы не можете сделать, потому что, как вы сказали, никого нет подпись), или явно указывайте этот тип при вызове, что было бы грязно.

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

    void SetResolverMethod<T>( Expression<Func<T,object>> expr );

    ...

    SetResolverMethod<ISomeInterface>( x => x.GetNameById(0) )

Метод SetResolverMethod на самом деле не выполнит выражение, а только проанализирует его - следовательно, ваш метод фактически не будет выполнен.

Это то, что вам нужно?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...