Menu
Coddy logo textTech

Upcasting y Downcasting

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 29 de 70.

Al trabajar con jerarquías de herencia, a menudo es necesario realizar conversiones entre tipos base y derivados. Upcasting convierte un tipo derivado a su tipo base, mientras que downcasting hace lo contrario.

El upcasting es implícito y siempre seguro porque se garantiza que una clase derivada tiene todo lo que la clase base tiene:

Dog myDog = new Dog();
Animal animal = myDog;  // Upcasting - implícito, siempre funciona

El downcasting requiere una conversión explícita y puede fallar en tiempo de ejecución si el objeto no es realmente del tipo al que se está realizando la conversión:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - funciona porque realmente es un Dog

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

Para realizar una conversión descendente de forma segura, use la palabra clave is para comprobar el tipo primero, o use as que devuelve null en lugar de lanzar una excepción:

if (animal is Dog d)
{
    d.Bark();  // Seguro - d solo está disponible si la comprobación tiene éxito
}

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

El enfoque de coincidencia de patrones is es preferido en el C# moderno porque combina la comprobación de tipo y la conversión en un solo paso, haciendo que su código sea más seguro y limpio.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de inspección de vehículos que demuestre cómo el upcasting y el downcasting te permiten trabajar de forma flexible con objetos en una jerarquía de herencia. Crearás diferentes tipos de vehículos y escribirás código que identifique e interactúe de forma segura con tipos de vehículos específicos.

Organizarás tu código en cuatro archivos:

  • Vehicle.cs: Define una clase base Vehicle en el espacio de nombres Inspection. Cada vehículo tiene una propiedad LicensePlate (string) establecida a través de un constructor. Incluye un método llamado GetBasicInfo() que devuelva "Vehicle: {LicensePlate}".
  • Car.cs: Define una clase Car en el espacio de nombres Inspection que herede de Vehicle. Los coches tienen una propiedad adicional NumberOfDoors (int). El constructor acepta tanto la matrícula como el número de puertas. Añade un método llamado Honk() que devuelva "{LicensePlate} honks: Beep beep!".
  • Motorcycle.cs: Define una clase Motorcycle en el espacio de nombres Inspection que herede de Vehicle. Las motocicletas tienen una propiedad HasSidecar (bool). El constructor acepta la matrícula y el estado del sidecar. Añade un método llamado Rev() que devuelva "{LicensePlate} revs: Vroom!".
  • Program.cs: En tu archivo principal, crearás vehículos y practicarás tanto el upcasting como el downcasting seguro. Crea un Car y una Motorcycle utilizando valores de entrada, luego almacena ambos en un array de referencias de Vehicle (upcasting). Recorre el array y, para cada vehículo, imprime su información básica. Luego usa la palabra clave is con coincidencia de patrones (pattern matching) para realizar un downcast seguro: si es un Car, llama a Honk(); si es una Motorcycle, llama a Rev().

Recibirás cuatro entradas:

  • Matrícula del coche
  • Número de puertas
  • Matrícula de la motocicleta
  • Tiene sidecar (true o false)

Imprime la salida en este formato para cada vehículo del array:

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

Por ejemplo, si las entradas son ABC-123, 4, XYZ-789, y false, la salida debería ser:

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

¡Observa cómo todos los vehículos se almacenan como referencias de Vehicle (upcasting), pero puedes descubrir de forma segura sus tipos reales y acceder a métodos específicos del tipo utilizando la sintaxis de coincidencia de patrones is para el downcasting!

Hoja de referencia

Al trabajar con jerarquías de herencia, el upcasting convierte un tipo derivado en su tipo base, mientras que el downcasting convierte un tipo base en un tipo derivado.

El upcasting es implícito y siempre seguro:

Dog myDog = new Dog();
Animal animal = myDog;  // Upcasting - implícito, siempre funciona

El downcasting requiere una conversión explícita y puede fallar en tiempo de ejecución:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - funciona porque realmente es un Dog

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

Downcasting seguro utilizando la palabra clave is con coincidencia de patrones (preferido):

if (animal is Dog d)
{
    d.Bark();  // Seguro - d solo está disponible si la comprobación tiene éxito
}

Downcasting seguro utilizando la palabra clave as (devuelve null si la conversión falla):

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

Pruébalo tú mismo

using System;
using Inspection;

class Program
{
    public static void Main(string[] args)
    {
        // Leer las entradas
        string carPlate = Console.ReadLine();
        int numberOfDoors = Convert.ToInt32(Console.ReadLine());
        string motorcyclePlate = Console.ReadLine();
        bool hasSidecar = Convert.ToBoolean(Console.ReadLine());
        
        // TODO: Crear un objeto Car usando carPlate y numberOfDoors
        
        // TODO: Crear un objeto Motorcycle usando motorcyclePlate y hasSidecar
        
        // TODO: Crear un arreglo de referencias de Vehicle que contenga ambos vehículos (upcasting)
        
        // TODO: Recorrer el arreglo y para cada vehículo:
        //   - Imprimir el resultado de GetBasicInfo()
        //   - Usar la palabra clave 'is' con pattern matching para realizar un downcast de forma segura:
        //     - Si es un Car, llamar e imprimir Honk()
        //     - Si es un Motorcycle, llamar e imprimir Rev()
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos