Menu
Coddy logo textTech

Upcasting e downcasting

Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 29 di 70.

Quando lavori con gerarchie di ereditarietà, spesso devi convertire i tipi base e derivati. Il casting verso l'alto converte un tipo derivato nel suo tipo base, mentre il casting verso il basso fa il contrario.

L'upcasting è implicito e sempre sicuro, perché è garantito che una classe derivata abbia tutto ciò che ha la classe base:

Dog myDog = new Dog();
Animal animal = myDog;  // Upcasting: implicito, funziona sempre

Il downcasting richiede un cast esplicito e può non riuscire durante l’esecuzione se l’oggetto non è effettivamente del tipo in cui lo stai convertendo:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - funziona perché in realtà è un Dog

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

Per eseguire un downcast in modo sicuro, usa la parola chiave is per controllare prima il tipo, oppure usa as, che restituisce null invece di generare un'eccezione:

if (animal is Dog d)
{
    d.Bark();  // Sicuro - d è disponibile solo se il controllo riesce
}

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

L'approccio di confronto dei pattern is è preferibile nel C# moderno perché combina il controllo del tipo e il cast in un unico passaggio, rendendo il codice più sicuro e pulito.

challenge icon

Sfida

Facile

Costruiamo un sistema di ispezione dei veicoli che dimostri come l’upcasting e il downcasting ti permettono di lavorare in modo flessibile con gli oggetti in una gerarchia di ereditarietà. Creerai diversi tipi di veicoli e scriverai codice che identifica in modo sicuro i tipi specifici di veicoli e interagisce con essi.

Organizzerai il codice in quattro file:

  • Vehicle.cs: Definisci una classe base Vehicle nello spazio dei nomi Inspection. Ogni veicolo ha una proprietà LicensePlate (string) impostata tramite un costruttore. Includi un metodo chiamato GetBasicInfo() che restituisce "Vehicle: {LicensePlate}".
  • Car.cs: Definisci una classe Car nello spazio dei nomi Inspection che eredita da Vehicle. Le auto hanno una proprietà aggiuntiva NumberOfDoors (int). Il costruttore accetta sia la targa sia il numero di porte. Aggiungi un metodo chiamato Honk() che restituisce "{LicensePlate} honks: Beep beep!".
  • Motorcycle.cs: Definisci una classe Motorcycle nello spazio dei nomi Inspection che eredita da Vehicle. Le motociclette hanno una proprietà HasSidecar (bool). Il costruttore accetta la targa e lo stato del sidecar. Aggiungi un metodo chiamato Rev() che restituisce "{LicensePlate} revs: Vroom!".
  • Program.cs: Nel tuo file principale, creerai dei veicoli e farai pratica sia con l’upcasting sia con il downcasting sicuro. Crea una Car e una Motorcycle usando i valori di input, quindi memorizzale entrambe in un array di riferimenti Vehicle (upcasting). Scorri l’array e stampa le informazioni di base di ciascun veicolo. Poi usa la parola chiave is con il pattern matching per eseguire il downcasting in modo sicuro: se è una Car, chiama Honk(); se è una Motorcycle, chiama Rev().

Riceverai quattro input:

  • Targa dell’auto
  • Numero di porte
  • Targa della motocicletta
  • Ha un sidecar (true o false)

Stampa l’output in questo formato per ciascun veicolo nell’array:

{GetBasicInfo() result}
{Honk() or Rev() result based on actual type}

Per esempio, se gli input sono ABC-123, 4, XYZ-789 e false, l’output dovrebbe essere:

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

Nota come tutti i veicoli sono memorizzati come riferimenti Vehicle (upcasting), ma puoi individuarne in sicurezza i tipi effettivi e accedere ai metodi specifici del tipo usando la sintassi del pattern matching is per il downcasting!

Provalo tu

using System;
using Inspection;

class Program
{
    public static void Main(string[] args)
    {
        // Leggi gli input
        string carPlate = Console.ReadLine();
        int numberOfDoors = Convert.ToInt32(Console.ReadLine());
        string motorcyclePlate = Console.ReadLine();
        bool hasSidecar = Convert.ToBoolean(Console.ReadLine());
        
        // TODO: Crea un oggetto Car usando carPlate e numberOfDoors
        
        // TODO: Crea un oggetto Motorcycle usando motorcyclePlate e hasSidecar
        
        // TODO: Crea un array di riferimenti Vehicle contenente entrambi i veicoli (upcasting)
        
        // TODO: Scorri l'array e, per ogni veicolo:
        //   - Stampa il risultato di GetBasicInfo()
        //   - Usa la parola chiave 'is' con il pattern matching per eseguire un downcast in modo sicuro:
        //     - Se è un Car, chiama Honk() e stampane il risultato
        //     - Se è un Motorcycle, chiama Rev() e stampane il risultato
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C# online