The ‘L’ in SOLID design principles is for Liskov’s Substitution Principle. The gist of it is that objects of a superclass should be able to be replaced with objects of a subclass without altering the correctness of the program.

In keeping with our zoo program, if we have a Bird class with a Fly() method, what happens to flightless birds?

According to the LSP, if a program is written with a list of “Bird” objects and a “Penguin” object is added to the list, the program should still work correctly without any modification.

This is because the “Penguin” object can be used in place of a “Bird” object without causing any issues, even though the “Penguin” object cannot fly and throws an exception when the “fly()” method is called.

// Base class for all birds in the zoo
public class Bird
{
    public virtual void Fly()
    {
        Console.WriteLine("Bird is flying");
    }
}

// Subclass for penguins
public class Penguin : Bird
{
    public override void Fly()
    {
        throw new Exception("Penguins cannot fly");
    }
}

// Usage example
List<Bird> birds = new List<Bird>();
birds.Add(new Bird());
birds.Add(new Bird());
birds.Add(new Penguin());
foreach (Bird bird in birds)
{
    bird.Fly();
}

In this case, birds list holds 3 Bird objects and one Penguin object. When the Fly() method is called on each element of the birds list, it will throw an exception for the Penguin object and will print “Bird is flying” for the other 3 Bird objects.