Liskov Substitution Principle in C#: Subclass Without Surprises

· 7 min

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:

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:

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.