Liskov Substitution Principle with a good C# example

LSP is about following the contract of the base class.

You can for instance not throw new exceptions in the sub classes as the one using the base class would not expect that. Same goes for if the base class throws ArgumentNullException if an argument is missing and the sub class allows the argument to be null, also a LSP violation.

Here is an example of a class structure which violates LSP:

public interface IDuck
{
   void Swim();
   // contract says that IsSwimming should be true if Swim has been called.
   bool IsSwimming { get; }
}
public class OrganicDuck : IDuck
{
   public void Swim()
   {
      //do something to swim
   }

   bool IsSwimming { get { /* return if the duck is swimming */ } }
}
public class ElectricDuck : IDuck
{
   bool _isSwimming;

   public void Swim()
   {
      if (!IsTurnedOn)
        return;

      _isSwimming = true;
      //swim logic  

   }

   bool IsSwimming { get { return _isSwimming; } }
}

And the calling code

void MakeDuckSwim(IDuck duck)
{
    duck.Swim();
}

As you can see, there are two examples of ducks. One organic duck and one electric duck. The electric duck can only swim if it’s turned on. This breaks the LSP principle since it must be turned on to be able to swim as the IsSwimming (which also is part of the contract) won’t be set as in the base class.

You can of course solve it by doing something like this

void MakeDuckSwim(IDuck duck)
{
    if (duck is ElectricDuck)
        ((ElectricDuck)duck).TurnOn();
    duck.Swim();
}

But that would break Open/Closed principle and has to be implemented everywhere (and thefore still generates unstable code).

The proper solution would be to automatically turn on the duck in the Swim method and by doing so make the electric duck behave exactly as defined by the IDuck interface

The solution with turning on the duck inside the Swim method can have side effects when working with the actual implementation (ElectricDuck). But that can be solved by using a explicit interface implementation. imho it’s more likely that you get problems by NOT turning it on in Swim since it’s expected that it will swim when using the IDuck interface

EXAMPLE OF VALID LISKOVS PRINCIPLE IMPLEMENTATION

public interface IDuck
{
    bool IsTurnedOn { get; set; }
    void Swim();
    void MakeDuckSwim();
}

public class Duck : IDuck
{
    public bool IsTurnedOn
    {
        get { return true; }
        set { value = true; }
    }

    public void Swim()
    {
        //do something to swim
    }
    private void TurnOn() 
    {
        //do nothing already on
    }
    public void MakeDuckSwim() 
    {
        Swim();
    }
}

public class ElectricDuck : IDuck
{
    public bool IsTurnedOn {get; set;}

    public void Swim()
    {
        if (!IsTurnedOn)
            TurnOn();

        //swim logic  
    }
    private void TurnOn()
    {
        IsTurnedOn = true;
    }
    public void MakeDuckSwim() 
    {
        if (!IsTurnedOn)
            TurnOn();

        Swim();
    }       
}

Then this will always work and follows all SOLID principles:

    duck.MakeDuckSwim();