The Liskov Substitution Principle (LSP) states that child class objects should be able to replace parent class objects without compromising application integrity. What this means essentially, is that we should put an effort to create such derived class objects which can replace objects of the base class without modifying its behavior. If we don’t, our application might end up being broken.

Does this make sense to you?

To make things clear, we are going to use a simple „Sum Calculator“ example, which will help us to understand how to implement the LSP better.

To download the source code for this project, check out the Liskov Substitution Principle Project Source Code.

To read about other SOLID principles, check out our SOLID Principles page.

This article is divided into the following sections:

- Initial Project
- Creating a Better Solution
- Implementing the Liskov Substitution Principle
- What We Gain By Implementing the Liskov Substitution Principle
- Conclusion

## Initial Project

In this example, we are going to have an array of numbers and a base functionality to sum all the numbers from that array. But let’s say we need to sum just even or just odd numbers.

How would we implement that? Let’s see one way to do it:

public class SumCalculator { protected readonly int[] _numbers; public SumCalculator(int[] numbers) { _numbers = numbers; } public int Calculate() => _numbers.Sum(); }

public class EvenNumbersSumCalculator: SumCalculator { public EvenNumbersSumCalculator(int[] numbers) :base(numbers) { } public new int Calculate() => _numbers.Where(x => x % 2 == 0).Sum(); }

Now if we test this solution, whether we calculate the sum of all the numbers or the sum of just even numbers, we are going to get the correct result for sure:

class Program { static void Main(string[] args) { var numbers = new int[] { 5, 7, 9, 8, 1, 6, 4 }; SumCalculator sum = new SumCalculator(numbers); Console.WriteLine($"The sum of all the numbers: {sum.Calculate()}"); Console.WriteLine(); EvenNumbersSumCalculator evenSum = new EvenNumbersSumCalculator(numbers); Console.WriteLine($"The sum of all the even numbers: {evenSum.Calculate()}"); } }

The result is:

## Creating a Better Solution

As we can see, this is working just fine. But what is wrong with this solution then?

Why are we trying to fix it?

Well, as we all know, if a child class inherits from a parent class, then the child class **is a** parent class. Having that in mind, we should be able to store a reference to an `EvenNumbersSumCalculator`

as a `SumCalculator`

variable and nothing should change. So, let’s check that out:

SumCalculator evenSum = new EvenNumbersSumCalculator(numbers); Console.WriteLine($"The sum of all the even numbers: {evenSum.Calculate()}");

As we can see, we are not getting the expected result because our variable `evenSum`

is of type `SumCalculator`

which is a higher order class (a base class). This means that the `Count`

method from the `SumCalculator`

will be executed. So, this is not right, obviously, because our child class is not behaving as a substitute for the parent class.

Luckily, the solution is quite simple. All we have to do is to implement small modifications to both of our classes:

public class SumCalculator { protected readonly int[] _numbers; public SumCalculator(int[] numbers) { _numbers = numbers; } public virtual int Calculate() => _numbers.Sum(); }

public class EvenNumbersSumCalculator: SumCalculator { public EvenNumbersSumCalculator(int[] numbers) :base(numbers) { } public override int Calculate() => _numbers.Where(x => x % 2 == 0).Sum(); }

As a result, when we start our solution, everything works as expected and the sum of even numbers is 18 again.

So, let’s explain this behavior. If we have a child object reference stored in a parent object variable and call the `Calculate`

method, the compiler will use the `Calculate`

method of the parent class. But right now because the `Calculate`

method is defined as „virtual“ and is overridden in the child class, that method in the child class will be used instead.

## Implementing the Liskov Substitution Principle

Still, the behavior of our derived class has changed and it can’t replace the base class. So we need to upgrade this solution by introducing the `Calculator`

abstract class:

public abstract class Calculator { protected readonly int[] _numbers; public Calculator(int[] numbers) { _numbers = numbers; } public abstract int Calculate(); }

Then we have to change our other classes:

public class SumCalculator : Calculator { public SumCalculator(int[] numbers) :base(numbers) { } public override int Calculate() => _numbers.Sum(); }

public class EvenNumbersSumCalculator: Calculator { public EvenNumbersSumCalculator(int[] numbers) :base(numbers) { } public override int Calculate() => _numbers.Where(x => x % 2 == 0).Sum(); }

Excellent. Now we can start making calls towards these classes:

class Program { static void Main(string[] args) { var numbers = new int[] { 5, 7, 9, 8, 1, 6, 4 }; Calculator sum = new SumCalculator(numbers); Console.WriteLine($"The sum of all the numbers: {sum.Calculate()}"); Console.WriteLine(); Calculator evenSum = new EvenNumbersSumCalculator(numbers); Console.WriteLine($"The sum of all the even numbers: {evenSum.Calculate()}"); } }

We will again have the same result, 40 for all the numbers and 18 for the even numbers. But now, we can see that we can store any subclass reference into a base class variable and the behavior won’t change which is the goal of LSP.

## What We Gain By Implementing the LSP

By implementing the LSP, we are keeping our functionality intact and still having our subclasses act as a substitute to a base class.

Also, we encourage the code reusability by implementing the LCP and having better project maintenance as well.

## Conclusion

We can see that implementing the LSP is not that complicated but just the opposite. Most of us probably already implemented this principle many times in our code without knowing its name because in the object-oriented world Polymorphism is quite a big thing.

I enjoyed reading your post. It is always hard to come up with good, small, examples showing violations to SOLID principles and how to fix these.

There will always be exceptions to the solutions, consider for example if you have a method that expects a SumCalculator as argument and have a body like this:

public static void VerifySum(SumCalculator c)

{

if (c.Sum() != 40)

throw new ApplicationException($"Invalid sum: {sum}");

}

This will pass for a SumCalculator but fail for an EvenSumCalculator, hence the EvenSumCalculator still violates LSP. In order to fix this you would need to create a completely abstract base class without any default implementation of Sum.

I would suggest reading Uncle Bob’s book Agile Principles, Patterns, and Practices in C# for a good example on this topic.

Thank you for this suggestion. I am trying to make examples as simple as possible, due to easier understanding for the readers without any knowledge about this topic or any other topic at all. And I must say, I am not a big fun of Circle Square examples. All the best.

I don’t really understand the Liskov principle – surely when you create a class hierarchy by it’s very definition each layer of the hierarchy gets more targeted or specialised? So surely you’re never going to code

SumCalculator evenSum = new EvenNumbersSumCalculator(numbers);

because you’ve explicitly desgned the child class’s Calculate() method to do a different job – to me this just seems like seriously bad programming.

I’ll admit I’m a bit old school, having leaned my coding in the days of the mainframe when OO didn’t even exist but I do try to adhere to these modern principles as most of them make perfect sense – except this one…. so what am I missing?