blog
Ottorino Bruni  

Liskov Substitution Principle (LSP) in C#

In my previous articles I wrote about Solid Principles in C#.

In this article, I am going to show you when and how to use the Liskov Substitution Principle in C# with an example project. You can find the repository on GitHub.

The master branch shows the initial code used in the example.  There are separate tags and branches for each of the all solid principles that you can review or download as well. Here are links you can use to jump to these tagged versions in your browser:

What is the Liskov Substitution Principle (LSP) in C#?

The Liskov Substitution Principle is one of the SOLID design principles. We can always reuse the definition from Wikipedia but this time will be hard to fully understand…

Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.

We can transform this sentence in:

If S is a subtype of T, then objects of type T should be replaced with the objects of type S.

Which simply stated means that:

Subtypes must be substitutable for their base types.

How to detect Liskov Substitution Principle (LSP) Violation?

  • Type checking with is or as in polymorphic code.
foreach(var reviewer in reviewers)
{
    if(reviewer is MobileDeviceReviewer)
    {
        reviewer.PrintMobileDevice();
        break;
    }
    reviewer.PrintDevice();
}
  • Null checking.
foreach(var reviewer in reviewers)
{
    if(reviewer == null)
    {
        Console.WriteLine("Reviewer not found!");
        break;
    }
    reviewer.PrintDevice();
}
  • NotImplementedException.
interface INotificationService 
{ 
    void SendEmail(); 
    void SendSms(); 
} 

class NotificationService : INotificationService 
{ 
    public void SendEmail() 
    { 
        Console.Write("SendEmail");
    } 
    
    public void SendSms() 
    {
        throw new NotImplementedException();
    }
}

Why should you use the Liskov Substitution Principle (LSP)?

  • Liskov Substitution Principle (LSP) violations are code smell. Maybe we have generalised a concept prematurely and created a superclass where it is not needed.

How we can refactor the code applying the Liskov Substitution Principle (LSP)?

We have done well in applying the Open Closed Principle (OCP) and this time we don’t have to do anything. Previously we created the UnknownDeviceReviewer class instead of returning null. This allowed us not to violate Liskov Substitution Principle (SRP)

public class ReviewerFactory
{
  public Reviewer Create(Device device, DeviceService service)
  {
    switch (device.Type)
    {
      case DeviceType.Mobile:
        return new MobileDeviceReviewer(service, service.Log);
      case DeviceType.Tablet:
        return new TabletDeviceReviewer(service, service.Log);
      case DeviceType.Desktop:
        return new DesktopDeviceReviewer(service, service.Log);
      case DeviceType.IoT:
        return new IoTDeviceReviewer(service, service.Log);
      default:
        // return null;
        return new UnknownDeviceReviewer(service, service.Log);
    }
  }
}

Why should you NOT use the Liskov Substitution Principle (LSP)?

LSP can become an anti-pattern, meaning sometimes the added complexity is not worth the tradeoff.

 

Please have a look at how I have refactored my previous code here LSP-END

If you think your friends/network would find this useful, please share it with them. I’d really appreciate it.

Thanks for reading! ????

 

 

Leave A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.