When developers hear terms like IoC, DI, and DIP, confusion often arises because they sound similar and are sometimes used interchangeably. However, each concept addresses software flexibility and maintainability from a slightly different perspective. Let’s break them down.
![Ioc-DI-DIP]()
1. Inversion of Control (IoC)
Definition
Inversion of Control is a design principle where the control of program flow is inverted compared to traditional programming. Instead of the application controlling the flow, the control is given to a framework, container, or external entity.
Example (Traditional Approach vs IoC)
Without IoC (Tight coupling):
public class UserService {
private UserRepository _repo;
public UserService() {
_repo = new UserRepository(); // Service decides how to create dependency
}
}
With IoC (Inversion of Control):
public class UserService {
private UserRepository _repo;
public UserService(UserRepository repo) {
_repo = repo; // Control of dependency creation is inverted
}
}
Here, instead of UserService
creating the UserRepository
, some external controller (e.g., an IoC container) provides it.
Key Idea: IoC is about who controls the flow (developer vs framework).
2. Dependency Injection (DI)
Definition
Dependency Injection is a design pattern to implement IoC. It focuses on how dependencies are provided to a class, rather than letting the class create them internally.
Types of Dependency Injection
Constructor Injection – dependencies are passed via constructor.
Setter Injection – dependencies are set through properties.
Interface Injection – dependencies are passed via interface methods.
Example
public interface IUserRepository {
void Save(string userName);
}
public class SqlUserRepository : IUserRepository {
public void Save(string userName) {
Console.WriteLine("User saved in SQL DB");
}
}
public class UserService {
private readonly IUserRepository _repo;
// Constructor Injection
public UserService(IUserRepository repo) {
_repo = repo;
}
public void Register(string userName) {
_repo.Save(userName);
}
}
In this case, the UserService
doesn’t create SqlUserRepository
. Instead, the dependency is injected from outside (e.g., via IoC container).
Key Idea: DI is a technique/pattern to achieve IoC.
3. Dependency Inversion Principle (DIP)
Definition
Dependency Inversion is the ‘D’ in SOLID principles. It states:
High-level modules should not depend on low-level modules.
Both should depend on abstractions (interfaces).
Abstractions should not depend on details; details should depend on abstractions.
Example
Without DIP (Tightly Coupled):
public class UserService {
private SqlUserRepository _repo = new SqlUserRepository();
public void Register(string userName) {
_repo.Save(userName); // Direct dependency on low-level class
}
}
With DIP (Loosely Coupled via Abstraction):
public interface IUserRepository {
void Save(string userName);
}
public class SqlUserRepository : IUserRepository {
public void Save(string userName) {
Console.WriteLine("User saved in SQL DB");
}
}
public class MongoUserRepository : IUserRepository {
public void Save(string userName) {
Console.WriteLine("User saved in MongoDB");
}
}
public class UserService {
private readonly IUserRepository _repo;
public UserService(IUserRepository repo) {
_repo = repo; // depends on abstraction, not concrete implementation
}
public void Register(string userName) {
_repo.Save(userName);
}
}
Now, UserService
can work with any repository that implements IUserRepository
(SQL, Mongo, etc.).
Key Idea: DIP is a principle ensuring modules depend on abstractions, not details.
How They Relate
IoC → A broad principle about inverting control from the application to the framework/container.
DI → A concrete pattern/technique to implement IoC.
DIP → A principle from SOLID ensuring high-level modules depend on abstractions, not concrete implementations.
👉 In practice:
We apply DIP to design our classes.
We use DI (constructor/property injection) to provide dependencies.
We rely on IoC containers (like Autofac, Unity, or .NET Core’s built-in container) to manage and inject dependencies automatically.
Quick Analogy
IoC: You don’t cook at home; instead, you go to a restaurant where the chef controls the cooking process.
DI: You tell the waiter what you want (dependencies injected).
DIP: The restaurant menu is based on types of dishes (abstractions), not on specific ingredients (concrete details).
✅ Now, we can say:
"IoC is a principle, DI is a pattern to implement IoC, and DIP is a SOLID principle ensuring our design is flexible by depending on abstractions. Together, they promote loose coupling, testability, and scalability."