Menu
Coddy logo textTech

Upcasting & Downcasting

Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy — Lektion 29 von 70.

Beim Arbeiten mit Vererbungshierarchien müssen Sie häufig zwischen Basis- und abgeleiteten Typen konvertieren. Upcasting konvertiert einen abgeleiteten Typ in seinen Basistyp, während Downcasting das Gegenteil bewirkt.

Upcasting ist implizit und immer sicher, da eine abgeleitete Klasse garantiert alles besitzt, was die Basisklasse hat:

Dog myDog = new Dog();
Animal animal = myDog;  // Upcasting - implizit, funktioniert immer

Downcasting erfordert eine explizite Typumwandlung und kann zur Laufzeit fehlschlagen, wenn das Objekt nicht tatsächlich der Typ ist, in den Sie umwandeln:

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 ein Downcasting durchzuführen, verwenden Sie das Schlüsselwort is, um zuerst den Typ zu prüfen, oder verwenden Sie as, das null zurückgibt, anstatt eine Exception auszulösen:

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 is-Pattern-Matching-Ansatz wird in modernem C# bevorzugt, da er die Typprüfung und die Typumwandlung in einem Schritt kombiniert, wodurch Ihr Code sowohl sicherer als auch sauberer wird.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Fahrzeug-Inspektionssystem bauen, das demonstriert, wie Upcasting und Downcasting es Ihnen ermöglichen, flexibel mit Objekten in einer Vererbungshierarchie zu arbeiten. Sie werden verschiedene Fahrzeugtypen erstellen und Code schreiben, der spezifische Fahrzeugarten sicher identifiziert und mit ihnen interagiert.

Sie werden Ihren Code in vier Dateien organisieren:

  • Vehicle.cs: Definieren Sie eine Basisklasse Vehicle im Namespace Inspection. Jedes Fahrzeug hat eine Eigenschaft LicensePlate (string), die über einen Konstruktor gesetzt wird. Fügen Sie eine Methode namens GetBasicInfo() hinzu, die "Vehicle: {LicensePlate}" zurückgibt.
  • Car.cs: Definieren Sie eine Klasse Car im Namespace Inspection, die von Vehicle erbt. Autos haben eine zusätzliche Eigenschaft NumberOfDoors (int). Der Konstruktor akzeptiert sowohl das Kennzeichen als auch die Anzahl der Türen. Fügen Sie eine Methode namens Honk() hinzu, die "{LicensePlate} honks: Beep beep!" zurückgibt.
  • Motorcycle.cs: Definieren Sie eine Klasse Motorcycle im Namespace Inspection, die von Vehicle erbt. Motorräder haben eine Eigenschaft HasSidecar (bool). Der Konstruktor akzeptiert das Kennzeichen und den Beiwagen-Status. Fügen Sie eine Methode namens Rev() hinzu, die "{LicensePlate} revs: Vroom!" zurückgibt.
  • Program.cs: In Ihrer Hauptdatei erstellen Sie Fahrzeuge und üben sowohl Upcasting als auch sicheres Downcasting. Erstellen Sie ein Car und ein Motorcycle unter Verwendung von Eingabewerten und speichern Sie beide in einem Array von Vehicle-Referenzen (Upcasting). Durchlaufen Sie das Array in einer Schleife und geben Sie für jedes Fahrzeug seine Basisinformationen aus. Verwenden Sie dann das Schlüsselwort is mit Pattern Matching für ein sicheres Downcasting: Wenn es ein Car ist, rufen Sie Honk() auf; wenn es ein Motorcycle ist, rufen Sie Rev() auf.

Sie erhalten vier Eingaben:

  • Auto-Kennzeichen
  • Anzahl der Türen
  • Motorrad-Kennzeichen
  • Hat Beiwagen (true oder false)

Geben Sie 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 sind, sollte die Ausgabe wie folgt aussehen:

Vehicle: ABC-123
ABC-123 honks: Beep beep!
Vehicle: XYZ-789
XYZ-789 revs: Vroom!

Beachten Sie, wie alle Fahrzeuge als Vehicle-Referenzen gespeichert werden (Upcasting), Sie aber ihre tatsächlichen Typen sicher entdecken und auf typspezifische Methoden zugreifen können, indem Sie die is-Pattern-Matching-Syntax für das Downcasting verwenden!

Spickzettel

Beim Arbeiten mit Vererbungshierarchien konvertiert Upcasting einen abgeleiteten Typ in seinen Basistyp, während Downcasting einen Basistyp in einen abgeleiteten Typ konvertiert.

Upcasting erfolgt implizit und ist immer sicher:

Dog myDog = new Dog();
Animal animal = myDog;  // Upcasting - implicit, always works

Downcasting erfordert eine explizite Typumwandlung (Cast) und kann zur Laufzeit fehlschlagen:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - works because it's really a Dog

Animal cat = new Cat();
Dog wrong = (Dog)cat;   // Throws InvalidCastException!

Sicheres Downcasting unter Verwendung des is-Schlüsselworts mit Pattern Matching (bevorzugt):

if (animal is Dog d)
{
    d.Bark();  // Safe - d is only available if check passes
}

Sicheres Downcasting unter Verwendung des as-Schlüsselworts (gibt null zurück, wenn die Umwandlung fehlschlägt):

Dog maybeDog = animal as Dog;
if (maybeDog != null)
{
    maybeDog.Bark();
}

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
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung