Search code examples
c#listoopinheritancepolymorphism

How to use a list of specialized objects being instances of types that inherits from the same class in C#?


Let's suppose I have the classes Bus and Truck, which inherit from Vehicle:

class Vehicle
{
    public string Model { get; set; }
}
class Bus : Vehicle 
{
    public Bus(string model, int passengers)
    {
        Model = model;
        MaxPassengers = passengers;
    }
    public int MaxPassengers { get; set; }
}
class Truck : Vehicle
{
    public Truck(string model, int weight)
    {
        Model = model;
        MaxWeight = weight;
    }
    public int MaxWeight { get; set; }
}

That being said, I want to allow the user to create new Truck or Bus classes and want to save them. The best way I could come up with was making a List, but I have to make it to accept both Truck and Bus objects.

At first I thought about making a Vehicle list. This is what I came up with:

class Program
{
    static void Main(string[] args)
    {
        List<Vehicle> allVehicles = new List<Vehicle>();

        Console.Write("[Bus] Insert model: ");
        string busModel = Console.ReadLine();

        Console.Write("[Bus] Insert max passengers: ");
        int busPassengers = Convert.ToInt32(Console.ReadLine());

        Console.Write("[Truck] Insert model: ");
        string truckModel = Console.ReadLine();

        Console.Write("[Truck] Insert weight capacity: ");
        int truckWeight = Convert.ToInt32(Console.ReadLine());

        allVehicles.Add(new Bus(busModel, busPassengers));
        allVehicles.Add(new Truck(truckModel, truckWeight));
    }
}

The code above compiles, but I can't access their specific properties (MaxPassengers of Bus objects and MaxWeight of Truck objects). Casting doesn't seem to work either. The following statement does not compile:

Console.WriteLine((Bus)allVehicles[0].MaxPassengers);

Am I missing something? Do I have to make a list for each class?


Solution

  • All is fine and clean with the code provided.

    You simply need to add brackets for the cast else it try to cast MaxPassengers and that fails:

    if ( allVehicles[0] is Bus )
      Console.WriteLine(((Bus)allVehicles[0]).MaxPassengers);
    

    Or explicitly convert:

    if ( allVehicles[0] is Bus )
      Console.WriteLine((allVehicles[0] as Bus).MaxPassengers);
    

    Null-conditional operator can be used too to avoid the if:

    Console.WriteLine((allVehicles[0] as Bus)?.MaxPassengers);
    

    Also you can use pattern-matching with C# 7+:

    if ( allVehicles[0] is Bus bus)
      Console.WriteLine(bus.MaxPassengers);
    

    You can filter the collection too:

    using System.Linq;
    
    var allBus = allVehicles.OfType<Bus>();
    
    foreach ( var bus in allBus )
      Console.WriteLine(bus.MaxPassengers);