Использование строго типизированного метода в качестве аргумента без указания параметров - PullRequest
5 голосов
/ 08 ноября 2011

Можно ли передать строго типизированное имя метода в качестве лямбда-выражения без указания параметров и / или скобок?

Например, если у меня есть следующий метод:

public class CalleeClass
{
    public void MethodA(obj param1, obj param2)
    {
        ...
    }
}

Я хотел бы вызвать этот метод в другом месте через:

return new MyClass<CalleeClass>(c => c.MethodA); //Note: no ()'s or arguments

Где MyClass будет отвечать, скажем, за маршрутизацию MVC с использованием имени метода в качестве цели.Цель здесь состоит в том, чтобы мы хотели иметь возможность использовать строго типизированные представления с помощью методов контроллера, и я не хочу предоставлять «глупые» параметры, которые не используются.

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

public void MyClass<T>(Expression<Action<T>> action)
{
    var methodName = (action.Body as MethodCallExpression).Method.Name;
}

РЕДАКТИРОВАТЬ: Извините за путаницу,но я сначала попытался упростить проблему, включив в нее только то, что, как мне показалось, вам нужно, и при этом пропустил некоторую ключевую информацию.Конечная цель здесь состоит в том, чтобы MyClass получил обобщенное выражение типа + лямбда, и лямбда-выражение может передавать строго типизированное имя метода без создания экземпляра объекта.-MB

Ответы [ 3 ]

2 голосов
/ 08 ноября 2011

Вы можете фактически передать метод без параметров:

class PassActionTest
{
    public void Test( )
    {
        var c = new C();
        var myClass =  new MyClass(c.MethodA); 
    }
}

class MyClass
{
    public MyClass(Action<object,object> action)
    {
        string methodName = action.Method.Name;
    }
}

class C
{
    public void MethodA(object param1, object param2)
    {
    }
}

EDIT : Согласно EDIT Мэтта Бекмана, класс, содержащий MethodA, создавать не следует. Мое новое решение:

class PassActionTest
{
    public void Test()
    {
        var myClass = new MyClass(c => c.MethodA);
    }
}

class MyClass
{
    public MyClass(Expression<Func<C, Action<object, object>>> expr)
    {
        UnaryExpression unaryExpr = (UnaryExpression)expr.Body;
        MethodCallExpression methodCallExpr = (MethodCallExpression)unaryExpr.Operand;
        ConstantExpression constantExpr = (ConstantExpression)methodCallExpr.Arguments[2];
        MethodInfo methodInfo = (MethodInfo)constantExpr.Value;
        string methodName = methodInfo.Name;
    }

}

class C
{
    public void MethodA(object param1, object param2)
    {
    }
}

Анализировать выражение немного сложно, но я проверил его, и оно работает.

1 голос
/ 08 ноября 2011

Если вам просто нужно имя метода, я бы порекомендовал использовать Delegate (http://msdn.microsoft.com/en-us/library/system.delegate.aspx):

public MyClass(Delegate action)
{
    var methodName = action.Method.Name;
}

. Это работает, за исключением того, что, я думаю, вам нужно будет указать тип делегата при его передаче:

{
    ...
    return new MyClass((Action<object,object>)c.MethodA);
}

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

0 голосов
/ 08 ноября 2011

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

public delegate void MethodADelegate(object param1, object param2);

public MyClass(MethodADelegate methodParam)
{
    //use the methodParam parameter
}

В качестве альтернативы вы можете использовать делегат Action <>, присутствующий в .Net, как предложено @ Olivier

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