Liskov Substitution Principle in C#: Subclass Without Surprises
Inheritance Without Betrayal
Inheritance is powerfulâbut with great power comes⊠well, you know the rest.
Ever swapped in a subclass and everything broke quietly? Thatâs a violation of the Liskov Substitution Principle (LSP)âthe âLâ in SOLID.
Objects of a superclass should be replaceable with objects of its subclasses without breaking the application. â Barbara Liskov
You miss 100% of the principles you ignore. â Me, channeling Michael Scottâ â Sathish Kumar Saravanan
Letâs unpack what that really means, using some straightforward C# examples and a healthy dose of practicality.
Whatâs the Big Idea?
When you inherit from a base class, youâre making a promise:
You can use me anywhere youâd use the base class, and things will still work as expected.
The moment a subclass starts throwing exceptions, skipping behavior, or changing meaningâyouâve broken that promise. Your design is fragile, even if the compiler says itâs fine.
Letâs look at a real-world example.
A Violation in Disguise
Imagine youâre building a system that handles documents:
public class Document
{
public virtual void Print()
{
Console.WriteLine("Printing document...");
}
}
Now letâs say we want to support digital-only documents:
public class DigitalDocument : Document
{
public override void Print()
{
throw new NotSupportedException("Digital documents can't be printed.");
}
}
Uh oh.
Sure, it compiles. But if someone uses DigitalDocument
in a place expecting a Document
, things break.
Thatâs exactly what LSP warns us about.
â Refactor to Respect LSP
Instead of forcing everything into a single hierarchy, letâs define capabilities more explicitly.
public interface IPrintable
{
void Print();
}
public class PaperDocument : IPrintable
{
public void Print()
{
Console.WriteLine("Printing paper document...");
}
}
public class DigitalDocument
{
public void Open()
{
Console.WriteLine("Opening digital document...");
}
}
Now DigitalDocument
never pretends to be printable. And PaperDocument
cleanly implements what it can actually do.
No surprise exceptions. No broken expectations. Everyoneâs behaving themselves.
Why This Matters in the Real World
Violating LSP leads to:
- đš Unexpected runtime errors
- đ§Ș Tests that pass for base classes but fail for subclasses
- đ§± Code that becomes harder to extend safely
Respecting LSP keeps your inheritance trees clean and your codebase honest. Subclasses donât have to do everything, but they shouldnât pretend to either.
A Quick LSP Check
Ask yourself:
- Can I pass this subclass wherever the base class is expected⊠and still trust the behavior?
- Does this subclass silently remove or alter functionality?
- Would a user of the base class be surprised by this subclass?
If the answerâs âuh⊠maybe,â itâs time to refactor.
Final Thoughts
The Liskov Substitution Principle is really about predictability.
Inheritance is meant to give you power, not headaches. When you design subclasses that follow LSP, your systems become safer, more understandable, and easier to refactor.
Donât build traps disguised as child classes. Build confidence. Build clarity.
If your subclass breaks the rules of the base class, itâs not inheritanceâitâs sabotage.