C # Überladen der Methode und generische Schnittstelle [duplizieren]

8

Ich bin verwirrt von einem Problem, das wir in unserem Projekt haben. Ich habe versucht, es zu vereinfachen, um den Effekt zu reproduzieren:

%Vor%

Für mich sieht das gut aus, aber der Compiler beschwert sich beim letzten Aufruf, weil er versucht DoTheFoo<T>(T bar) anstelle von DoTheFoo<T>(IFoo<T> foo) zu schreiben und beschwert sich, dass der Argumenttyp nicht passt.

  • Wenn ich die Methode DoTheFoo<T>(T bar) lösche, funktioniert der letzte Aufruf!
  • Wenn ich es in DoTheFoo<T>(Foo<T> foo) ändere, funktioniert es, aber ich kann das nicht verwenden

Es ist nicht zu schwer, dies in unserem aktuellen Code zu umgehen. Aber es ist a) seltsam und b) schade, dass wir diese beiden überladenen Methoden nicht haben können.

Gibt es eine allgemeine Regel, die dieses Verhalten erklärt? Ist es möglich, es zum Laufen zu bringen (außer den Methoden unterschiedliche Namen zu geben)?

    
Stefan Steinegger 26.03.2013, 13:58
quelle

1 Antwort

7

Es ist nur eine Frage der Typinferenz, die in Kombination mit der Überladungsauflösung nicht zu Ihren Gunsten funktioniert. Es ist einfach zu beheben, indem Sie das Argument type explizit angeben - es ist kein Cast erforderlich:

%Vor%

Normalerweise bin ich nervös vor Überlastungen, die allerdings ziemlich unterschiedliche Parametertypen erfordern. Oft ist der Code einfacher, wenn Sie den Methoden unterschiedliche Namen geben. Abgesehen von allem anderen müssen Ihre Leser nicht gleichzeitig versuchen, eine Überladungsauflösung durchzuführen, um die Art der Inferenz zu erkennen ...

EDIT: Ich glaube das Problem ist, dass die Reihenfolge so funktioniert:

  • Beide Methoden wurden gefunden
  • Typ-Inferenz wird auf beide Methoden angewendet ohne die Einschränkungen zu überprüfen - so erhalten wir für die erste Methode T = Foo<Bar> und für die zweite Methode T = Bar . Beide Methoden sind an dieser Stelle anwendbar.
  • Es wird eine Überladungsauflösung durchgeführt, die entscheidet, dass die erste Methode die spezifischste ist.
  • Nur nachdem die Überladungsauflösung durchgeführt wurde, wird die Einschränkung für T aktiviert - und das scheitert, weil es keine Referenzkonvertierung von Bar nach IFoo gibt.

Es gibt einen Eric Lippert Blog-Post darüber, warum die Sprache auf diese Weise entworfen ist , ein blog post Ich schrieb darüber und einen Artikel, den ich über das Überladen im Allgemeinen geschrieben habe . Jeder von ihnen kann oder kann nicht helfen:)

BEARBEITEN: Die Typinferenz wird für einen Moment beiseite gelassen. Der Grund, warum die erste Methode spezifischer ist, ist, dass wir in einem Fall von Foo<Bar> in Foo<Bar> konvertieren und in der anderen von Foo<Bar> bis IFoo<Bar> . Gemäß Abschnitt 7.5.3.3 der C # 5-Spezifikation:

  

Gegeben ist eine implizite Umwandlung C1, die von einem Ausdruck E in einen Typ T1 konvertiert, und eine implizite Umwandlung C2, die von einem Ausdruck E in einen Typ T2 konvertiert, C1 ist eine bessere Umwandlung als C2, wenn mindestens eines der folgenden gilt :   - E hat einen Typ S und eine Identitätskonvertierung existiert von S nach T1, aber nicht von S nach T2   - ...

Die Identitätskonvertierung erfolgt von einem Typ zu sich selbst, wobei der Fall für die erste Überladung ist, aber nicht für die zweite. Die erste Konvertierung ist also besser.

    
Jon Skeet 26.03.2013, 14:07
quelle

Tags und Links