DEV Community

Libin Tom Baby
Libin Tom Baby

Posted on

SOLID Principles in C# — A Practical, Real‑World Guide for .NET Developers


SOLID Principles in C#

SOLID is one of those topics that shows up in every senior .NET interview — and for good reason. These five principles help you write cleaner, more maintainable, and more scalable code. But the real value comes from understanding how to apply them in real-world .NET systems.

This guide breaks down each principle with simple definitions, C# examples, and practical scenarios you can use in interviews or production code.


S — Single Responsibility Principle (SRP)

A class should have one and only one reason to change.

What it means

A class should do one thing.

Not “mostly one thing.”

Not “one thing plus a helper.”

Just one responsibility.

Bad example

public class OrderService
{
    public void CreateOrder(Order order) { }
    public void SendEmail(Order order) { }
}
Enter fullscreen mode Exit fullscreen mode

This class handles business logic and emailing — two responsibilities.

Good example

public class OrderService
{
    public void CreateOrder(Order order) { }
}

public class EmailService
{
    public void SendEmail(Order order) { }
}
Enter fullscreen mode Exit fullscreen mode

Real‑world scenario

  • Logging mixed with business logic
  • Controllers doing validation + mapping + business logic
  • Services doing too much

SRP makes your code testable and easier to maintain.


O — Open/Closed Principle (OCP)

Software entities should be open for extension but closed for modification.

What it means

You should be able to add new behavior without changing existing code.

Bad example

public class PaymentProcessor
{
    public void Pay(string method)
    {
        if (method == "CreditCard") { }
        else if (method == "PayPal") { }
        else if (method == "Crypto") { }
    }
}
Enter fullscreen mode Exit fullscreen mode

Every new payment method requires modifying this class.

Good example

public interface IPaymentMethod
{
    void Pay();
}

public class CreditCard : IPaymentMethod { public void Pay() { } }
public class PayPal : IPaymentMethod { public void Pay() { } }

public class PaymentProcessor
{
    public void Pay(IPaymentMethod method) => method.Pay();
}
Enter fullscreen mode Exit fullscreen mode

Real‑world scenario

Adding new features without breaking existing ones — especially in enterprise systems.


L — Liskov Substitution Principle (LSP)

Subclasses should be substitutable for their base classes.

What it means

If class B inherits from class A, you should be able to use B anywhere A is expected — without breaking behavior.

Bad example

public class Bird
{
    public virtual void Fly() { }
}

public class Penguin : Bird
{
    public override void Fly() => throw new Exception("Penguins can't fly");
}
Enter fullscreen mode Exit fullscreen mode

This violates LSP — a Penguin is not a Bird in this model.

Good example

public abstract class Bird { }
public class FlyingBird : Bird { public void Fly() { } }
public class Penguin : Bird { }
Enter fullscreen mode Exit fullscreen mode

Real‑world scenario

Inheritance hierarchies that break behavior or introduce exceptions.


I — Interface Segregation Principle (ISP)

Clients should not be forced to depend on interfaces they do not use.

What it means

Small, focused interfaces are better than large, bloated ones.

Bad example

public interface IWorker
{
    void Work();
    void Eat();
}
Enter fullscreen mode Exit fullscreen mode

Robots don’t eat.

Good example

public interface IWorkable { void Work(); }
public interface IFeedable { void Eat(); }
Enter fullscreen mode Exit fullscreen mode

Real‑world scenario

Large service interfaces with 20+ methods — most implementations only use a few.


D — Dependency Inversion Principle (DIP)

Depend on abstractions, not concrete implementations.

What it means

High-level modules should not depend on low-level modules.

Both should depend on interfaces.

Bad example

public class ReportService
{
    private readonly FileLogger _logger = new FileLogger();
}
Enter fullscreen mode Exit fullscreen mode

Tightly coupled.

Good example

public class ReportService
{
    private readonly ILogger _logger;
    public ReportService(ILogger logger) => _logger = logger;
}
Enter fullscreen mode Exit fullscreen mode

Now you can inject:

  • FileLogger
  • DatabaseLogger
  • CloudLogger

Real‑world scenario

Dependency Injection in ASP.NET Core is built entirely on DIP.


Putting SOLID Together — A Real .NET Example

Imagine building an order processing system:

  • SRP → OrderService handles orders only
  • OCP → Add new payment methods without modifying existing code
  • LSP → Subclasses behave correctly when substituted
  • ISP → Interfaces are small and focused
  • DIP → Services depend on abstractions, not concrete classes

This leads to cleaner architecture, easier testing, and safer refactoring.


Interview‑Ready Summary

  • SRP → One responsibility
  • OCP → Extend, don’t modify
  • LSP → Subtypes must behave correctly
  • ISP → Small interfaces
  • DIP → Depend on abstractions

A strong interview answer:

“SOLID helps create maintainable, scalable, and testable systems. It reduces coupling, improves extensibility, and keeps code clean as the system grows.”


Add‑On

Where Did SOLID Come From? A Brief Origin Story

SOLID didn’t appear out of nowhere — it has a clear lineage in software engineering history.

The principles were originally introduced by Robert C. Martin (Uncle Bob), one of the most influential figures in modern software craftsmanship. He coined the acronym SOLID in the early 2000s to group together five existing object‑oriented design principles that had been discussed in academic and professional circles for years.

The ideas themselves were heavily inspired by earlier work from:

  • Bertrand Meyer (creator of Eiffel) — especially the Open/Closed Principle
  • Barbara Liskov — whose Liskov Substitution Principle became the “L” in SOLID
  • Tom DeMarco, Grady Booch, and others — pioneers of structured and OO design

SOLID gained massive popularity because:

  • Uncle Bob promoted it through books, talks, and the Agile movement
  • It aligned perfectly with Test‑Driven Development (TDD)
  • It helped teams build maintainable, scalable systems
  • It became a cornerstone of Clean Architecture and modern .NET design

Today, SOLID is considered foundational knowledge for senior developers, architects, and anyone building long‑lived enterprise systems.


Top comments (0)