2009-09-29 8 views
28

Ich habe eine seltsame Situation, wo ich den Namen des Delegaten als Zeichenfolge erhalten muss. Ich habe eine generische Methode, die so aussieht.Name der Aktion/Func Delegat

private T Get<T>(T task, Action<T> method) where T : class 
{ 
    string methodName = method.Method.Name //Should return Bark 
} 

und ich rufe es wie dieses

private void MakeDogBark() 
{ 
    dog = Get(dog, x=>x.Bark()); 
} 

Aber statt des Sehens "Bark" Ich sehe diese "<MakeDogBark>b__19". So sieht es aus, als ob es mir den Methodennamen gibt, der den anfänglichen Anruf statt des Namens des Delegaten machte.

Wer weiß, wie man das macht?

Antwort

45

Es gibt Ihnen den Namen der Methode, die die Aktion des Delegaten ist. Das wird zufällig mit einem Lambda-Ausdruck implementiert.

Sie haben derzeit einen Delegierten, der der Reihe nach Anrufe Bark. Wenn Sie Bark direkt verwenden möchten, müssen Sie einen offenen Delegaten für die Bark-Methode erstellen, die möglicherweise nicht sehr einfach ist. Nehmen wir an, Sie möchten es wirklich nennen. Wenn Sie es nicht nennen müssen, oder Sie wissen, dass es auf jeden Fall auf dem ersten Argument aufgerufen wird, könnten Sie verwenden:

private T Get<T>(T task, Action method) where T : class 
{ 
    string methodName = method.Method.Name //Should return Bark 
} 

private void MakeDogBark() 
{ 
    dog = Get(dog, dog.Bark); 
} 

Sie könnte runden diese erhalten, indem die Parameter ein Ausdruck Baum statt eines Delegaten, aber dann würde es nur funktionieren, wenn der Lambda-Ausdruck sowieso nur ein Methodenaufruf wäre.

+0

die schön gearbeitet. Ich musste es nicht ausführen, aber ich musste den Methodennamen an eine Klasse übergeben, die etwas damit machen würde. Anstatt nur eine Zeichenfolge zu nehmen, wollte ich die Typsicherheit des Anrufers, die mir eine echte Methode geben muss. Wie immer bist du der Mann :) – Adam

+0

@Jon Gibt es eine Möglichkeit, das gleiche mit einer generischen Methode zu tun? –

+0

@ArnabChakraborty: Sie müssten auch das Argument type angeben, aber ich glaube, es würde dann funktionieren. Kann es jetzt aber nicht so einfach ausprobieren. –

5

Sie können, indem die Parameter ein Ausdruck anstelle eines Delegierten den Namen des Methodenaufruf erhalten, genau wie Jon

erwähnt
private T Get<T>(T task, Expression<Action<T>> method) where T : class 
{ 
    if (method.Body.NodeType == ExpressionType.Call) 
    { 
     var info = (MethodCallExpression)method.Body; 
     var name = info.Method.Name; // Will return "Bark" 
    } 

    //..... 
} 
+2

Sie sagen also, dass es heißen würde "Get (x => x.DoSomething (Arg1))"? Was, wenn Sie nur die Methode als Delegat in einer typsicheren Weise übergeben wollten, aber ohne sie aufzurufen, wie zum Beispiel "Get (x => x.DoSomething)"? – bflemi3

+0

Ja. Gibt es eine Möglichkeit, den 'nameof'-Operator von C# 6 in C# 5 zu machen? –