2011-11-08 9 views
5

È possibile passare il nome fortemente tipizzato di un metodo come espressione lambda senza fornire anche i parametri e/o le parentesi?Utilizzo di un metodo fortemente tipizzato come argomento senza specificare i parametri

Per esempio, se ho il seguente metodo:

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

Vorrei chiamare questo metodo altrove tramite:

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

Dove MiaClasse sarebbe responsabile per, diciamo, MVC instradamento utilizzando il nome del metodo come destinazione. L'obiettivo qui è che vogliamo essere in grado di utilizzare le viste fortemente tipizzate tramite i metodi del controller e non voglio dover fornire parametri "stupidi" che non vengono utilizzati.

Attualmente, sto usando un codice simile al seguente per usare i nomi dei metodi, ma questo stile richiede ancora il passaggio di argomenti falsi e/o parentesi.

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

EDIT: Ci scusiamo per la confusione, ma inizialmente ho cercato di semplificare il problema solo tra cui quello che ho pensato che avresti bisogno, ed in tal modo lasciato fuori alcune informazioni chiave. L'obiettivo finale qui è avere MyClass ricevere un tipo generico + espressione lambda, e l'espressione lambda può passare nel nome del metodo fortemente tipizzato senza creare un'istanza di un oggetto. -MB

+0

Non si possono impostare parametri opzionali? Inoltre: MethodCallExpression non funzionerà a meno che non abbia la parentesi, ne sono abbastanza sicuro. – chemicalNova

+0

I parametri non sono stupidi; sono usati dal compilatore ... –

+0

Senza offesa per i parametri, ma abbiamo solo bisogno del nome del metodo per il routing, e sembra strano dare l'impressione che stiamo creando un'istanza di un oggetto.Non sono convinto che questo sia possibile, ed è per questo che sono venuto qui. :) –

risposta

2

Si può effettivamente passare il metodo senza parametri:

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: Secondo EDIT di Matt Beckman, la classe che contiene MethodA non deve essere istanziato. La mia nuova soluzione è:

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

È un po 'complicato analizzare l'espressione, ma l'ho provato e funziona.

+0

Nel tentativo di semplificare il problema qui, penso di aver dimenticato che questa riga dovrebbe essere: _return new MyClass (c => c.MethodA) _, poiché non voglio istanziare la classe che ha il metodo MethodA. Vedi le modifiche sopra. –

+0

@MattBeckman: vedere la modifica alla mia risposta originale. –

+1

Vedere [questo commento] (http://stackoverflow.com/questions/8225302/get-the-name-of-a-method-using-an-expression#comment30751822_8228144) e [questa risposta] (http: // stackoverflow .com/a/26976055/1270174) per l'utilizzo su runtime v4.5. –

0

È possibile dichiarare un delegato corrispondente alla firma del metodo MethodA() e utilizzare il delegato come parametro al costruttore della classe MyClass

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

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

In alternativa, è possibile utilizzare l'azione <> delegato presente in .Net come suggerito da @Olivier

1

Se hai solo bisogno del nome del metodo, ti consiglio di utilizzare Delegate (http://msdn.microsoft.com/en-us/library/system.delegate.aspx) :

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

Questo funziona tranne che penso è necessario specificare il tipo di delegato quando si passa in:

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

Questo terremo tutto strongly-typed tale che refactoring funzionerà, anche.

Problemi correlati