2014-10-14 4 views
11

Wenn Sie verzweigen, um eine Funktion auszuwählen, kann es sinnvoll sein, den ternären Operator zu verwenden, um eine Funktion auszuwählen. Dies ist jedoch nicht möglich. Warum?Warum arbeitet der C# -Ternäroperator nicht mit Delegierten?

public class Demo { 
    protected bool branch; 
    protected void demo1() {} 
    protected void demo2() {} 
    public Action DoesntWork() { 
     return branch ? demo1 : demo2; 
    } 
} 

Der Compiler erzeugt den folgenden Fehler:

Cannot implicitly convert type `method group' to `System.Action' 

Antwort

16

Das Problem ist, dass demo1 ist kein einfacher Ausdruck, es ist eine Methode. Und Methoden können überschrieben werden, so ist es nicht tatsächlich eine Methode, es ist eine Methodengruppe. Betrachten Sie das folgende Beispiel:

public class Demo { 
    protected bool branch; 
    protected void demo1 (int) {} 
    protected void demo1() {} 
    protected void demo2() {} 
    public Action DoesntWork() { 
     return branch ? demo1 : demo2; //Error 
     return demo1; //ok 
    } 
} 

Nun demo1 ist überlastet, so das eine der beiden Versionen soll verwendet werden? Die Antwort ist, dass die überladene Funktion ausgewählt wird, indem der Kontext verwendet wird, in dem die Funktion verwendet wird.

In der return demo1 ist es offensichtlich, es erwartet eine Action.

Aber in der return branch? demo1 : demo2; ist der Kontext nicht so einfach. Der ternäre Operator versucht zunächst, den Typ demo1 mit dem von demo2 abzugleichen, aber das ist eine andere Methodengruppe, so dass es keine Hilfe gibt. Der Compiler schaut nicht darüber hinaus und schlägt fehl.

Die Lösung ist, die Art deutlich zu machen, aus der Methode Gruppe erwartet:

return branch? new Action(demo1) : demo2; 

return branch? (Action)demo1 : demo2; 

Action d1 = demo1; 
return branch? d1 : demo2; 
+1

+1 zur Erklärung, warum die Typinferenz ausfällt, und dass Sie eine Besetzung statt 'new' verwenden können. –

5

Sie müssen explizit die Delegierten des entsprechenden Typs erstellen. Normalerweise können Sie einfach demo1 verwenden, um auf eine System.Action zu verweisen, aber das liegt nur daran, dass der Compiler den Typ basierend auf der Verwendung ableiten kann und den Delegaten für Sie erstellt. In diesem Fall weiß der Compiler nicht, dass Ihre Methode innerhalb des ternären Operators in System.Action konvertiert werden sollte.

Wenn Sie diese Texte selbst liefern noch eines der Argumente, wird es funktionieren:

public Action DoesWork() 
{ 
    return branch ? demo1 : new Action(demo2); 
} 

Da diese new Action explizit für ein Argument zurückgibt, kann der Compiler ableiten, dass der andere zu einem System.Action angemessen umgesetzt werden sollte, und es wird erfolgreich kompiliert.

Verwandte Themen