2010-05-18 11 views
6

Dispatching Ich traf nur eine Situation, wo eine Methode Dispatch zweideutig war und fragte sich, ob jemand auf welcher Grundlage der Compiler erklären könnte (.NET 4.0.30319) wählt, wasC# Generisches überladene Methode mehrdeutig

interface IfaceA 
{ 

} 

interface IfaceB<T> 
{ 
    void Add(IfaceA a); 
    T Add(T t); 
} 

class ConcreteA : IfaceA 
{ 

} 

class abstract BaseClassB<T> : IfaceB<T> 
{ 
    public virtual T Add(T t) { ... } 
    public virtual void Add(IfaceA a) { ... } 
} 

class ConcreteB : BaseClassB<IfaceA> 
{ 
    // does not override one of the relevant methods 
} 

void code() 
{ 
    var concreteB = new ConcreteB(); 

    // it will call void Add(IfaceA a) 
    concreteB.Add(new ConcreteA()); 
} 

nennen Überlastung Warum warnt der Compiler mich überhaupt nicht oder warum kompiliert er überhaupt? Vielen Dank für Ihre Antworten.

+0

Was passiert, wenn Sie einen Rückgabewert vom Aufruf erwarten, d. H. 'Var result = concreteB.Add (new ConcreteA());'? –

+1

Weil Ihre generische Methode eine Rückgabe "Typ T" und die andere vom Typ "void" hat. Der Compiler kann zwischen ihnen unterscheiden. – KroaX

+0

der Compiler wird sich beschweren, dass 'var' nicht verwendet werden kann, weil er void nicht der implizit typisierten Variablen – Sebastian

Antwort

2

Aufruf Es folgt den Regeln in Abschnitt 7.5.3.2 des C# 4 specification („Better Funktionselement“).

Zuerst (naja, nachdem Sie gesehen haben, dass beide Methoden anwendbar sind) müssen wir die Konvertierungen von Argumenttypen zu Parametertypen überprüfen. In diesem Fall ist es ziemlich einfach, weil es nur ein Argument gibt. Weder die Konvertierung des Argumenttyps in den Parametertyp ist "besser", weil beide von ConcreteA in IfaceA konvertieren. Es bewegt sich daher auf die nächste Reihe von Kriterien auf, darunter diese:

Andernfalls, wenn MP spezifischere Parametertypen als MQ hat, dann ist MP besser als MQ. Seien {R1, R2, ..., RN} und {S1, S2, ..., SN} die uninstantiierten und nicht expandierten Parametertypen von MP und MQ. MP des Parametertypen sind spezifischer als MQ ist, wenn für jeden Parameter ist RX nicht weniger spezifisch als SX, und, für zumin dest einen Parameter, RX ist spezifischer als SX: spezifischer als SX:

  • Ein Typparameter ist weniger spezifisch als ein Nicht-Typparameter.
  • ...

Also auch wenn die Umwandlung gleich gut ist, wird die Überlastung mit IfaceA direkt (und nicht über Delegierten) „besser“ als da ein Parameter vom Typ IfaceA spezifischer ist als ein Parameter vom Typ T.

Es gibt keine Möglichkeit, den Compiler auf dieses Verhalten warnen zu lassen - es ist nur normale Überladungsauflösung.

+0

vertrauen Ok danke eine Million. Ich denke, das bedeutet, dass ich diese Spezifikation lesen werde. Ich bin nur ein Java-Konvertierer und muss C# für dieses Projekt verwenden. Obwohl ich denke, es ist nützlicher, aber jedes Feature, das ich fühle, fügt auch einige Randfälle hinzu mehr ... – Sebastian

1

Da der Compiler zuerst die spezifischste auswählt.

Was passiert, wenn Sie rufen wie so geschieht: Diese etwas erinnert mich an den "Typ-Inferenz a-go-go" in Jon Skeet's BrainTeaser

void code() 
{ 
    var concreteB = new ConcreteB(); 

    IfaceA x = concreteB.Add(new ConcreteA()); 
} 
+0

zuweisen kann. Aber warum würde' void Add (IfaceA a) 'spezifischer sein? Liegt es daran, dass ich das zurückgegebene Ergebnis nicht verwende?Und außerdem, weißt du, ob ich eine Compiler-Option habe, um mir eine Warnung zu geben? – Sebastian

+0

@sebgod: Sie können die Anweisung '# warning' verwenden, um eine Compiler-Warnung auszugeben. –

+0

Der Code wird nicht kompiliert, wenn ich 'IfaceA x = concreteB.Add (neue ConcreteA()) wählen;': kann nicht implizit zwischen IFaceA und void konvertieren – Sebastian

1

. Wenn Sie nicht wollen, den Compiler vertrauen, möchten Sie vielleicht seine Wahl zwingen, durch Add<ConcreteA>(new ConcreteA())

+0

Das ist, was mein Lehrer immer sagte mir, nie Ihrem Compiler – Sebastian

Verwandte Themen