Menu
Coddy logo textTech

Upcasting e Downcasting

Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 29 de 70.

Ao trabalhar com hierarquias de herança, você frequentemente precisa converter entre tipos base e derivados. Upcasting converte um tipo derivado para seu tipo base, enquanto o downcasting faz o oposto.

O upcasting é implícito e sempre seguro porque uma classe derivada tem a garantia de ter tudo o que a classe base possui:

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

Downcasting exige um cast explícito e pode falhar em tempo de execução se o objeto não for realmente o tipo para o qual você está convertendo:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - funciona porque é realmente um Dog

Animal cat = new Cat();
Dog wrong = (Dog)cat;   // Lança InvalidCastException!

Para realizar o downcast com segurança, use a palavra-chave is para verificar o tipo primeiro, ou use as que retorna null em vez de lançar uma exceção:

if (animal is Dog d)
{
    d.Bark();  // Seguro - d só está disponível se a verificação passar
}

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

A abordagem de correspondência de padrões is é preferida no C# moderno porque combina a verificação de tipo e a conversão (cast) em uma única etapa, tornando seu código mais seguro e limpo.

challenge icon

Desafio

Fácil

Vamos construir um sistema de inspeção de veículos que demonstra como o upcasting e o downcasting permitem que você trabalhe de forma flexível com objetos em uma hierarquia de herança. Você criará diferentes tipos de veículos e escreverá um código que identifica e interage com segurança com tipos específicos de veículos.

Você organizará seu código em quatro arquivos:

  • Vehicle.cs: Defina uma classe base Vehicle no namespace Inspection. Todo veículo possui uma propriedade LicensePlate (string) definida através de um construtor. Inclua um método chamado GetBasicInfo() que retorna "Vehicle: {LicensePlate}".
  • Car.cs: Defina uma classe Car no namespace Inspection que herda de Vehicle. Carros possuem uma propriedade adicional NumberOfDoors (int). O construtor aceita tanto a placa quanto a contagem de portas. Adicione um método chamado Honk() que retorna "{LicensePlate} honks: Beep beep!".
  • Motorcycle.cs: Defina uma classe Motorcycle no namespace Inspection que herda de Vehicle. Motocicletas possuem uma propriedade HasSidecar (bool). O construtor aceita a placa e o status do sidecar. Adicione um método chamado Rev() que retorna "{LicensePlate} revs: Vroom!".
  • Program.cs: No seu arquivo principal, você criará veículos e praticará tanto o upcasting quanto o downcasting seguro. Crie um Car e uma Motorcycle usando valores de entrada, depois armazene ambos em um array de referências de Vehicle (upcasting). Percorra o array e, para cada veículo, imprima suas informações básicas. Em seguida, use a palavra-chave is com correspondência de padrões (pattern matching) para realizar o downcasting com segurança: se for um Car, chame Honk(); se for uma Motorcycle, chame Rev().

Você receberá quatro entradas:

  • Placa do carro
  • Número de portas
  • Placa da motocicleta
  • Possui sidecar (true ou false)

Imprima a saída neste formato para cada veículo no array:

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

Por exemplo, se as entradas forem ABC-123, 4, XYZ-789, e false, a saída deve ser:

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

Observe como todos os veículos são armazenados como referências de Vehicle (upcasting), mas você pode descobrir com segurança seus tipos reais e acessar métodos específicos do tipo usando a sintaxe de correspondência de padrões is para downcasting!

Folha de consulta

Ao trabalhar com hierarquias de herança, o upcasting converte um tipo derivado para seu tipo base, enquanto o downcasting converte um tipo base para um tipo derivado.

Upcasting é implícito e sempre seguro:

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

Downcasting requer um cast explícito e pode falhar em tempo de execução:

Animal animal = new Dog();
Dog dog = (Dog)animal;  // Downcasting - funciona porque é realmente um Dog

Animal cat = new Cat();
Dog wrong = (Dog)cat;   // Lança InvalidCastException!

Downcasting seguro usando a palavra-chave is com correspondência de padrões (preferencial):

if (animal is Dog d)
{
    d.Bark();  // Seguro - d só está disponível se a verificação passar
}

Downcasting seguro usando a palavra-chave as (retorna null se o cast falhar):

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

Experimente você mesmo

using System;
using Inspection;

class Program
{
    public static void Main(string[] args)
    {
        // Ler as entradas
        string carPlate = Console.ReadLine();
        int numberOfDoors = Convert.ToInt32(Console.ReadLine());
        string motorcyclePlate = Console.ReadLine();
        bool hasSidecar = Convert.ToBoolean(Console.ReadLine());
        
        // TODO: Criar um objeto Car usando carPlate e numberOfDoors
        
        // TODO: Criar um objeto Motorcycle usando motorcyclePlate e hasSidecar
        
        // TODO: Criar um array de referências Vehicle contendo ambos os veículos (upcasting)
        
        // TODO: Percorrer o array e para cada veículo:
        //   - Imprimir o resultado de GetBasicInfo()
        //   - Usar a palavra-chave 'is' com pattern matching para fazer o downcast com segurança:
        //     - Se for um Car, chamar e imprimir Honk()
        //     - Se for um Motorcycle, chamar e imprimir Rev()
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos