Upcasting & Downcasting
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 29 von 70.
Beim Arbeiten mit Vererbungshierarchien musst du häufig zwischen Basis- und abgeleiteten Typen konvertieren. Upcasting konvertiert einen abgeleiteten Typ in seinen Basistyp, während Downcasting das Gegenteil bewirkt.
Upcasting erfolgt implizit und ist immer sicher, da eine abgeleitete Klasse garantiert alles besitzt, was die Basisklasse besitzt:
Dog myDog = new Dog();
Animal animal = myDog; // Upcasting - implizit, funktioniert immerEin Downcasting erfordert eine explizite Typumwandlung und kann zur Laufzeit fehlschlagen, wenn das Objekt nicht tatsächlich der Typ ist, in den du es umwandelst:
Animal animal = new Dog();
Dog dog = (Dog)animal; // Downcasting - funktioniert, weil es wirklich ein Dog ist
Animal cat = new Cat();
Dog wrong = (Dog)cat; // Wirft InvalidCastException!Um sicher nach unten zu casten, verwende zuerst das Schlüsselwort is, um den Typ zu überprüfen, oder verwende as, das statt eine Ausnahme auszulösen null zurückgibt:
if (animal is Dog d)
{
d.Bark(); // Sicher - d ist nur verfügbar, wenn die Prüfung erfolgreich ist
}
Dog maybeDog = animal as Dog;
if (maybeDog != null)
{
maybeDog.Bark();
}Der Musterabgleich mit is wird im modernen C# bevorzugt, weil er die Typprüfung und die Typumwandlung in einem Schritt kombiniert und deinen Code dadurch sowohl sicherer als auch übersichtlicher macht.
Aufgabe
EinfachErstellen wir ein Fahrzeuginspektionssystem, das zeigt, wie Upcasting und Downcasting dir ermöglichen, flexibel mit Objekten in einer Vererbungshierarchie zu arbeiten. Du erstellst verschiedene Fahrzeugtypen und schreibst Code, der bestimmte Fahrzeugarten sicher erkennt und mit ihnen interagiert.
Du organisierst deinen Code auf vier Dateien verteilt:
Vehicle.cs: Definiere eine BasisklasseVehicleim NamespaceInspection. Jedes Fahrzeug verfügt über eineLicensePlate-Eigenschaft (string), die über einen Konstruktor festgelegt wird. Füge eine Methode namensGetBasicInfo()hinzu, die"Vehicle: {LicensePlate}"zurückgibt.Car.cs: Definiere eine KlasseCarim NamespaceInspection, die vonVehicleerbt. Autos verfügen über eine zusätzlicheNumberOfDoors-Eigenschaft (int). Der Konstruktor akzeptiert sowohl das Kennzeichen als auch die Anzahl der Türen. Füge eine Methode namensHonk()hinzu, die"{LicensePlate} honks: Beep beep!"zurückgibt.Motorcycle.cs: Definiere eine KlasseMotorcycleim NamespaceInspection, die vonVehicleerbt. Motorräder verfügen über eineHasSidecar-Eigenschaft (bool). Der Konstruktor akzeptiert das Kennzeichen und den Beiwagenstatus. Füge eine Methode namensRev()hinzu, die"{LicensePlate} revs: Vroom!"zurückgibt.Program.cs: In deiner Hauptdatei erstellst du Fahrzeuge und übst sowohl Upcasting als auch sicheres Downcasting. Erstelle mithilfe von Eingabewerten einCarund einMotorcycleund speichere beide in einem Array vonVehicle-Referenzen (Upcasting). Durchlaufe das Array und gib für jedes Fahrzeug seine grundlegenden Informationen aus. Verwende anschließend das Schlüsselwortismit Pattern Matching, um sicher downzucasten: Wenn es sich um einCarhandelt, rufeHonk()auf; wenn es sich um einMotorcyclehandelt, rufeRev()auf.
Du erhältst vier Eingaben:
- Kennzeichen des Autos
- Anzahl der Türen
- Kennzeichen des Motorrads
- Beiwagen vorhanden (
trueoderfalse)
Gib die Ausgabe für jedes Fahrzeug im Array in diesem Format aus:
{GetBasicInfo() result}
{Honk() or Rev() result based on actual type}Wenn die Eingaben beispielsweise ABC-123, 4, XYZ-789 und false lauten, sollte die Ausgabe wie folgt aussehen:
Vehicle: ABC-123
ABC-123 honks: Beep beep!
Vehicle: XYZ-789
XYZ-789 revs: Vroom!Beachte, dass alle Fahrzeuge als Vehicle-Referenzen gespeichert werden (Upcasting), du aber ihre tatsächlichen Typen sicher ermitteln und mithilfe der is-Pattern-Matching-Syntax für das Downcasting typspezifische Methoden aufrufen kannst!
Probier es selbst
using System;
using Inspection;
class Program
{
public static void Main(string[] args)
{
// Eingaben lesen
string carPlate = Console.ReadLine();
int numberOfDoors = Convert.ToInt32(Console.ReadLine());
string motorcyclePlate = Console.ReadLine();
bool hasSidecar = Convert.ToBoolean(Console.ReadLine());
// TODO: Erstelle ein Car-Objekt unter Verwendung von carPlate und numberOfDoors
// TODO: Erstelle ein Motorcycle-Objekt unter Verwendung von motorcyclePlate und hasSidecar
// TODO: Erstelle ein Array von Vehicle-Referenzen, das beide Fahrzeuge enthält (Upcasting)
// TODO: Durchlaufe das Array in einer Schleife und für jedes Fahrzeug:
// - Gib das Ergebnis von GetBasicInfo() aus
// - Verwende das Schlüsselwort 'is' mit Pattern Matching für ein sicheres Downcasting:
// - Wenn es ein Car ist, rufe Honk() auf und gib es aus
// - Wenn es ein Motorcycle ist, rufe Rev() auf und gib es aus
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler