2 Stimmen

Funktioniert Polymorphismus nicht so, wie ich es mir vorgestellt habe?

Ich habe eine Superklasse, die Informationen über Autoaufkleber verarbeitet. Ich habe eine Unterklasse, die spezielle Aufkleberinformationen für eine Transaktion verwaltet. Ich habe eine spezielle Überschreibung in der Transaktion decal, die verwendet wird, um für bestimmte Dinge zu überprüfen, bevor ein decal # gesetzt werden kann. Das Problem, das ich habe, ist, dass ich manchmal Informationen über ein generisches Decal-Objekt abrufen und in mein Transaktions-Decal setzen muss. Zum Beispiel:

TransactionDecal myTransactionDecal = new TransactionDecal();
Decal myGenericDecal = new Decal();
myTransactionDecal = (TransactionDecal) myGenericDecal.getGenericDecal();

Aber ich erhalte einen Laufzeitfehler, der mir mitteilt, dass ich nicht zwischen den Typen umwandeln kann. Was genau mache ich falsch, und ist dies der richtige Weg, um es zu gehen? Vielen Dank!

3voto

Jeremy Smyth Punkte 22624

Das Prinzip der Substituierbarkeit besagt, dass jeder Typ durch sich selbst oder einen Subtyp substituiert werden kann.

Hier tun Sie das Gegenteil - Sie versuchen, eine Instanz des Supertyps in einer Variablen des Subtyps zu referenzieren (unter der Annahme, dass Decal die Superklasse und TransactionDecal die Subklasse ist).

Dies ist blockiert, da die Vererbung dazu dient, eine bestehende Klasse zu spezialisieren, d. h. die Schnittstelle zu erweitern; im Allgemeinen würde das Ersetzen einer Oberklasse die Schnittstelle einschränken, und dies würde Aufrufe von Methoden (über den referenzierenden Variablentyp) ermöglichen, die in der Oberklasse nicht implementiert sind.

1voto

jitter Punkte 52721

Dies ist nicht möglich, da Sie die weniger spezialisierte Klasse (Decal) in eine stärker spezialisierte Klasse (TransactionDecal) umwandeln würden. Das kann nicht funktionieren, da Sie jetzt Methoden auf Decal aufrufen könnten, die dort nicht implementiert sind (denken Sie nur an neu eingeführte Variablen in TransactionDecal, die von den neuen Methoden oder den überschriebenen Methoden verwendet werden), die es in einer Instanz von Decal gar nicht geben kann.

0voto

patros Punkte 7443

Jeremys Erklärung, warum das nicht funktioniert, trifft den Nagel auf den Kopf.

Wenn Sie dieses Problem umgehen wollen, können Sie transactionDecal nicht von Decal erben lassen, sondern eine Instanz von Decal enthalten. Auf diese Weise können Sie die interne Instanz auf das generische Decal festlegen, ohne dass Transaktionsdaten verloren gehen.

Es gibt natürlich auch andere Muster, aber dies ist eines der gängigsten Muster für die Behandlung dieser Art von Problemen.

0voto

JP Alioto Punkte 44283

Dies wird als Downcasting bezeichnet. Das ist eine ziemlich gute kurze Einführung wann es in Ordnung ist und wann nicht (in C# sowieso) ...

Animal a;
a = b;
Bird b = (Bird) a; // Okay

Dieser Code wird erfolgreich kompiliert. Zur Laufzeit führt der Cast-Operator eine Prüfung, um festzustellen, ob das Objekt, auf das verwiesen wird, wirklich vom Typ Bird ist. Wenn dies nicht der Fall ist, wird zur Laufzeit die InvalidCastException ausgelöst.

Aber Sie sollten es nicht tun müssen. Ihr abgeleiteter Typ sollte alles können, was Ihr Basistyp auch kann. Wenn Sie einen Basistyp haben und etwas wollen, das nur ein abgeleiteter Typ kann, dann sollten Sie besser eine Instanz eines abgeleiteten Typs dafür verwenden! :)

Bearbeiten per Kommentar: Es gibt keinen Grund, warum man nicht einen abgeleiteten Konstruktor bereitstellen kann, der eine Instanz einer Base nimmt und einen Abgeleiteten um diese herum baut (wie einen Standard-Abgeleiteten um eine bestimmte Base) ...

public D(B b)
{
}

Aber es klingt für mich so, als bräuchten Sie eine Schnittstelle oder Sie sollten die Anforderungen an Ihre Methodenparameter lockern. Wenn Ihre Methode mit einem Tier gut umgehen kann, gibt es keinen Grund, warum sie Sie zwingen sollte, ihr einen Vogel zu übergeben, was Ihre Methode zu tun scheint.

0voto

shizbiz Punkte 517

Anhand Ihres Beispiels sehen Sie hier, wie Polymorphismus implementiert werden kann:

// cast derived object as base object
Decal myGenericDecal = null;
TransactionDecal myTransactionDecal = TransactionDecal.GetTransactionDecal()
myGenericDecal = myTransactionDecal;

// cast base object to a derived object
TransactionalDecal newTransactionalDecal = null;
newTransactionalDecal = (TransactionalDecal)myGenericDecal;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X