Roadmap › SOLID Principles with Examples › Module: L, I and D
Lessons in this course (8)

5. D — Dependency Inversion Principle

Intermediate★ Must knowLesson 5 of 8
  1. High-level modules should not depend on low-level modules; both depend on abstractions.
  2. Abstractions should not depend on details; details depend on abstractions.
csharp
// ❌ High-level policy welded to a detail
public class OrderService
{
    private readonly SqlOrderRepository _repo = new SqlOrderRepository();   // can't test, can't swap
}

// ✅ Depend on an abstraction owned by the high-level layer
public interface IOrderRepository { Task AddAsync(Order o); }
public class OrderService(IOrderRepository repo)
{
    public Task PlaceAsync(Order o) => repo.AddAsync(o);
}
public class SqlOrderRepository(AppDbContext db) : IOrderRepository
{
    public async Task AddAsync(Order o) { db.Orders.Add(o); await db.SaveChangesAsync(); }
}

// Composition root (Program.cs)
builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>();
builder.Services.AddScoped<OrderService>();

DIP vs DI vs IoC:

  • DIP — the principle (depend on abstractions).
  • IoC (Inversion of Control) — the general idea that a framework/container controls object creation and flow, not your code.
  • DI (Dependency Injection) — the technique: dependencies are passed in (constructor, method or property injection), usually by an IoC container.