Upcasting & Downcasting
Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy — leçon 29 sur 70.
Lorsque vous travaillez avec des hiérarchies d'héritage, vous avez souvent besoin de effectuer des conversions entre les types de base et les types dérivés. L'upcasting convertit un type dérivé en son type de base, tandis que le downcasting fait l'inverse.
L'upcasting est implicite et toujours sûr car une classe dérivée est garantie de posséder tout ce que la classe de base possède :
Dog myDog = new Dog();
Animal animal = myDog; // Upcasting - implicite, fonctionne toujoursLe downcasting nécessite un transtypage explicite et peut échouer à l'exécution si l'objet n'est pas réellement du type vers lequel vous effectuez le transtypage :
Animal animal = new Dog();
Dog dog = (Dog)animal; // Downcasting - fonctionne car c'est réellement un Dog
Animal cat = new Cat();
Dog wrong = (Dog)cat; // Lève une InvalidCastException !Pour effectuer un downcast en toute sécurité, utilisez le mot-clé is pour vérifier d'abord le type, ou utilisez as qui renvoie null au lieu de lever une exception :
if (animal is Dog d)
{
d.Bark(); // Sûr - d n'est disponible que si la vérification réussit
}
Dog maybeDog = animal as Dog;
if (maybeDog != null)
{
maybeDog.Bark();
}L'approche de pattern matching is est privilégiée en C# moderne car elle combine la vérification de type et le transtypage en une seule étape, rendant votre code à la fois plus sûr et plus propre.
Défi
FacileConstruisons un système d'inspection de véhicules qui démontre comment l'upcasting et le downcasting vous permettent de travailler de manière flexible avec des objets dans une hiérarchie d'héritage. Vous allez créer différents types de véhicules et écrire du code qui identifie et interagit en toute sécurité avec des types de véhicules spécifiques.
Vous organiserez votre code sur quatre fichiers :
Vehicle.cs: Définissez une classe de baseVehicledans l'espace de nomsInspection. Chaque véhicule possède une propriétéLicensePlate(string) définie via un constructeur. Incluez une méthode appeléeGetBasicInfo()qui retourne"Vehicle: {LicensePlate}".Car.cs: Définissez une classeCardans l'espace de nomsInspectionqui hérite deVehicle. Les voitures ont une propriété supplémentaireNumberOfDoors(int). Le constructeur accepte à la fois la plaque d'immatriculation et le nombre de portes. Ajoutez une méthode appeléeHonk()qui retourne"{LicensePlate} honks: Beep beep!".Motorcycle.cs: Définissez une classeMotorcycledans l'espace de nomsInspectionqui hérite deVehicle. Les motos ont une propriétéHasSidecar(bool). Le constructeur accepte la plaque d'immatriculation et le statut du side-car. Ajoutez une méthode appeléeRev()qui retourne"{LicensePlate} revs: Vroom!".Program.cs: Dans votre fichier principal, vous créerez des véhicules et pratiquerez à la fois l'upcasting et le downcasting sécurisé. Créez uneCaret uneMotorcycleen utilisant les valeurs d'entrée, puis stockez les deux dans un tableau de référencesVehicle(upcasting). Parcourez le tableau et, pour chaque véhicule, affichez ses informations de base. Utilisez ensuite le mot-cléisavec le filtrage par motif (pattern matching) pour effectuer un downcasting sécurisé : s'il s'agit d'uneCar, appelezHonk(); s'il s'agit d'uneMotorcycle, appelezRev().
Vous recevrez quatre entrées :
- Plaque d'immatriculation de la voiture
- Nombre de portes
- Plaque d'immatriculation de la moto
- Possède un side-car (
trueoufalse)
Affichez la sortie dans ce format pour chaque véhicule du tableau :
{GetBasicInfo() result}
{Honk() or Rev() result based on actual type}Par exemple, si les entrées sont ABC-123, 4, XYZ-789, et false, la sortie devrait être :
Vehicle: ABC-123
ABC-123 honks: Beep beep!
Vehicle: XYZ-789
XYZ-789 revs: Vroom!Remarquez comment tous les véhicules sont stockés en tant que références Vehicle (upcasting), mais vous pouvez découvrir en toute sécurité leurs types réels et accéder aux méthodes spécifiques au type en utilisant la syntaxe de pattern matching is pour le downcasting !
Aide-mémoire
Lorsque vous travaillez avec des hiérarchies d'héritage, l'upcasting convertit un type dérivé en son type de base, tandis que le downcasting convertit un type de base en un type dérivé.
L'upcasting est implicite et toujours sûr :
Dog myDog = new Dog();
Animal animal = myDog; // Upcasting - implicite, fonctionne toujoursLe downcasting nécessite un transtypage explicite et peut échouer à l'exécution :
Animal animal = new Dog();
Dog dog = (Dog)animal; // Downcasting - fonctionne car c'est réellement un Dog
Animal cat = new Cat();
Dog wrong = (Dog)cat; // Lève une exception InvalidCastException !Downcasting sécurisé en utilisant le mot-clé is avec le filtrage par motif (préféré) :
if (animal is Dog d)
{
d.Bark(); // Sûr - d n'est disponible que si la vérification réussit
}Downcasting sécurisé en utilisant le mot-clé as (retourne null si le transtypage échoue) :
Dog maybeDog = animal as Dog;
if (maybeDog != null)
{
maybeDog.Bark();
}Essayez vous-même
using System;
using Inspection;
class Program
{
public static void Main(string[] args)
{
// Lire les entrées
string carPlate = Console.ReadLine();
int numberOfDoors = Convert.ToInt32(Console.ReadLine());
string motorcyclePlate = Console.ReadLine();
bool hasSidecar = Convert.ToBoolean(Console.ReadLine());
// TODO: Créer un objet Car en utilisant carPlate et numberOfDoors
// TODO: Créer un objet Motorcycle en utilisant motorcyclePlate et hasSidecar
// TODO: Créer un tableau de références Vehicle contenant les deux véhicules (upcasting)
// TODO: Parcourir le tableau et pour chaque véhicule :
// - Afficher le résultat de GetBasicInfo()
// - Utiliser le mot-clé 'is' avec le pattern matching pour effectuer un downcast sécurisé :
// - Si c'est une Car, appeler et afficher Honk()
// - Si c'est une Motorcycle, appeler et afficher Rev()
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesEspaces de noms et directivesIntro aux classes et objetsLe mot-clé 'this'Méthodes et paramètresChamps vs PropriétésConstructeursInitialiseurs d'objetsRécapitulatif - Calculatrice simple4Héritage
Syntaxe de base de l'héritage (:)Le mot-clé 'base'Mots-clés Virtual & OverrideClasses scelléesLa classe de base 'object'Récapitulatif - Hiérarchie des employés7Fonctionnalités avancées
Surcharge d'opérateursIndexeurs (this[])Redéfinition de ToString()Méthodes d'extensionRécapitulatif - Liste personnalisée10Patrons de conception - Partie 1
Introduction aux patrons de conceptionSingleton Thread-SafePatron FabriquePatron Observateur (Événements)Patron Stratégie2Propriétés et membres statiques
Propriétés auto-implémentéesPropriétés en lecture/écriture seuleChamps et méthodes statiquesClasses statiquesMembres à corps d'expression5Polymorphisme & Interfaces
Polymorphisme : Compilation vs ExécutionInterface vs Classe AbstraiteInterfaces MultiplesInterfaces ExplicitesUpcasting & DowncastingRécapitulatif - Calculateur de Formes8Concepts avancés de la POO
Composition plutôt qu'héritageGénériques (Classes et Méthodes)Délégués et ÉvénementsAttributs et RéflexionIDisposable et l'instruction usingBases de l'Injection de Dépendances11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Architecture des classes
Données d'instance vs statiquesMots-clés 'readonly' & 'const'Champs de supportRécapitulatif - Gestionnaire de compte bancaire6Encapsulation
Modificateurs d'accèsPropriétés pour l'encapsulationImplémentation du masquage de donnéesPatterns d'immuabilitéRécapitulatif - Dossiers d'étudiants12Projet : Système de gestion de bibliothèque
Structure du projetModèles Livre et Utilisateur