Im folgenden Code hätte ich erwartet, dass der Aufruf von a.Generate(v)
zum Aufrufen von V.Visit(A a)
geführt hätte, da, wenn Generate aufgerufen wird this
vom Typ A ist. Hoewever scheint this
als gesehen zu haben ein Inter
stattdessen.
Ist es möglich, das beabsichtigte Verhalten zu haben, ohne die (identische) Methode explizit in A
und B
und nur in der gemeinsamen Basisklasse zu implementieren? Wenn ja, wie kann es erreicht werden?
Bearbeiten
In den Antworten wurde vorgeschlagen, dass der obige Code nicht polymorph ist. Dem würde ich widersprechen. V.Visit
ist polymorph .
Sie erwarten, dass der Aufruf von v.Visit(this)
ermittelt, welche Überladung von Visit
basierend auf den Laufzeittypen von sowohl v
als auch% co_de aufgerufen werden soll %.
Sprachen, die diese Funktion haben, werden "double virtual dispatch" -Sprachen genannt. (Oder, wenn mehr als zwei Dinge berücksichtigt werden, werden sie als "multiple virtual dispatch" -Sprachen oder "multimethod" -Sprachen bezeichnet.)
C # ist keine doppelte virtuelle Dispatch-Sprache; es ist eine einzige virtuelle Dispatch-Sprache , wenn Dispatch-Entscheidungen zur Kompilierungszeit getroffen werden . Das heißt, die Entscheidung, welche Überladung zu wählen ist, basiert auf dem Laufzeit Typ des Empfängers , aber auf den Kompilierzeit Typen der Argumente .
In Ihrem Fall verwendet C # nicht einzelnen virtuellen Versand , da der Aufruf von this
gar nicht erst ein virtueller Anruf ist! Die Tatsache, dass der Aufruf von Visit
ein virtueller Aufruf war, ist völlig irrelevant, und die Tatsache, dass Generate
überladen ist, ist ebenfalls irrelevant. Der Versand an Visit
erfolgt nicht-virtuell , sodass die Dispatch-Logik vollständig auf dem Kompilierzeit -Typ des Empfängers, Visit
, und dem Argument basiert %Code%. Da bekannt ist, dass der Empfänger vom Typ v
ist und das Argument vom Typ this
ist, muss die Überladungsauflösung die bestmögliche Übereinstimmung auswählen, die nur für diese Information gilt . Es kann nicht die Versionen von V
auswählen, die Inter
oder Visit
benötigen, weil diese abgeleiteter sind als der bekannte Argumenttyp A
. Es muss die Überladung mit dem formalen Parameter weniger abgeleitet , B
, auswählen.
Wenn Sie einen doppelten virtuellen Versand in C # erreichen möchten, gibt es zwei Standardmethoden. Zuerst können Sie Inter
; Mit Base
wird die Analyse zur Laufzeit mit den Laufzeittypen durchgeführt. Übergeben Sie einfach den Empfänger und die Argumente an dynamic
und der Compiler wird sich darum kümmern. Dies verursacht jedoch erhebliche Leistungskosten.
Der zweite Standardweg ist das Besuchermuster , das Sie im Internet finden können. Ich vermute aufgrund der Namen Ihrer Methoden, dass Sie bereits versuchen, das Besuchermuster zu implementieren; Das ist nicht der richtige Weg.
Das ist kein polymorpher Code, polymorpher Code hat eine dynamische Bindung, die bestimmt, welche Methode zur Laufzeit aufgerufen wird. Beide Objekte müssen eine ähnliche Basisklasse mit virtuellen Methoden haben, um diese dynamische Bindung durchzuführen. Momentan ist Ihre Bindung statisch und wird zur Kompilierzeit bestimmt.
Das Problem ist, dass die Methode Generate
in der Klasse Iter
definiert ist. Wenn also die Methode Generate
aufgerufen wird, übergibt sie eine Referenz an eine Iter
.
Wenn Sie A
oder B
in übergeben möchten, machen Sie Generate
virtual und überschreiben Sie sie auf den Ebenen A
und B
, um den korrekt gewichteten Wert zu übergeben.
Was erwartest du genau?
%Vor%Irgendwie kompiliert der Compiler eine Version des Codes für v.Visit (this). Es kann nicht verschiedene Versionen für jede Aufrufinstanz gemäß dem tatsächlichen tpye des übergebenen Arguments kompilieren.
In einem polymorphen Design sind Inter und jede seiner abgeleiteten Klassen dafür verantwortlich, "persönliche" Dinge zu tun.
%Vor% wobei VisitedBy()
eine virtuelle Funktion ist.
Tags und Links c# polymorphism