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 sempreIl 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.
Sfida
FacileCostruiamo 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 baseVehiclenello spazio dei nomiInspection. Ogni veicolo ha una proprietàLicensePlate(string) impostata tramite un costruttore. Includi un metodo chiamatoGetBasicInfo()che restituisce"Vehicle: {LicensePlate}".Car.cs: Definisci una classeCarnello spazio dei nomiInspectionche eredita daVehicle. Le auto hanno una proprietà aggiuntivaNumberOfDoors(int). Il costruttore accetta sia la targa sia il numero di porte. Aggiungi un metodo chiamatoHonk()che restituisce"{LicensePlate} honks: Beep beep!".Motorcycle.cs: Definisci una classeMotorcyclenello spazio dei nomiInspectionche eredita daVehicle. Le motociclette hanno una proprietàHasSidecar(bool). Il costruttore accetta la targa e lo stato del sidecar. Aggiungi un metodo chiamatoRev()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 unaCare unaMotorcycleusando i valori di input, quindi memorizzale entrambe in un array di riferimentiVehicle(upcasting). Scorri l’array e stampa le informazioni di base di ciascun veicolo. Poi usa la parola chiaveiscon il pattern matching per eseguire il downcasting in modo sicuro: se è unaCar, chiamaHonk(); se è unaMotorcycle, chiamaRev().
Riceverai quattro input:
- Targa dell’auto
- Numero di porte
- Targa della motocicletta
- Ha un sidecar (
trueofalse)
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
}
}
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
1Fondamenti della programmazione orientata agli oggetti
File esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studentiEsercitati da solo: Compilatore C# online