2011-11-08 17 views
5

¿Es posible pasar el nombre fuertemente tipado de un método como una expresión lambda sin proporcionar también los parámetros y/o paréntesis?Uso de un método fuertemente tipado como argumento sin especificar parámetros

Por ejemplo, si tengo el siguiente método:

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

me gustaría llamar a este método en otros lugares a través de:

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

Dónde MiClase serían responsables de, digamos, MVC enrutamiento usando el nombre del método como el objetivo. El objetivo aquí es que queremos poder usar vistas fuertemente tipadas a través de métodos de control, y no quiero tener que proporcionar parámetros "tontos" que no se usen.

Actualmente, estoy usando un código similar al siguiente para usar los nombres de los métodos, pero este estilo todavía requiere pasar argumentos falsos y/o paréntesis.

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

EDIT: Lo siento por la confusión, pero inicialmente trató de simplificar el problema al incluir únicamente lo que pensé que había necesidad, y al hacerlo dejado fuera algo de información clave. El objetivo final aquí es que MyClass reciba un tipo genérico + expresión lambda, y la expresión lambda puede pasar en el nombre del método fuertemente tipado sin instanciar un objeto. -MB

+0

¿No se pueden establecer parámetros opcionales? Además: MethodCallExpression no funcionará a menos que tenga el paréntesis, estoy bastante seguro. – chemicalNova

+0

Los parámetros no son tontos; son utilizados por el compilador ... –

+0

Sin ofender a los parámetros, pero solo necesitamos el nombre del método para el enrutamiento, y parece extraño dar la impresión de que estamos instanciando un objeto.No estoy convencido de que esto sea posible, por eso vine aquí. :) –

Respuesta

2

En realidad puede pasar al método sin parámetros:

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) 
    { 
    } 
} 

EDITAR: Según EDITAR de Matt Beckman, la clase que contiene MethodA no debe ser instanciada. Mi nueva solución es:

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) 
    { 
    } 
} 

Es un poco complicado analizar la expresión, pero la he probado y funciona.

+0

Al intentar simplificar el problema aquí, creo que olvidé agregar que esta línea debería ser: _return new MyClass (c => c.MethodA) _, ya que no quiero crear una instancia de la clase que tiene el método MethodA. Ver los cambios arriba. –

+0

@MattBeckman: Vea la edición de mi respuesta original. –

+1

Ver [este comentario] (http://stackoverflow.com/questions/8225302/get-the-name-of-a-method-using-an-expression#comment30751822_8228144) y [esta respuesta] (http: // stackoverflow .com/a/26976055/1270174) para uso en tiempo de ejecución v4.5. –

0

Se puede declarar un delegado a juego de la firma del método MethodA() y utilizar el delegado como parámetro al constructor de la clase MiClase

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

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

Alternativamente, se puede utilizar la acción <> delegado presente en .Net como lo sugiere @Olivier

1

Si solo necesita el nombre del método, le recomiendo usar Delegate (http://msdn.microsoft.com/en-us/library/system.delegate.aspx) :

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

Esto funciona, excepto que creo que tendrá que especificar el tipo de delegado al pasar en:

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

Esto va a mantener todo inflexible-tal que refactorización va a funcionar, también.

Cuestiones relacionadas