Dependency Injection (DI) in C#:
Dependency Injection is a design pattern used to achieve Inversion of Control (IoC) between classes and their dependencies. Instead of a class creating its dependencies, they are provided from outside, typically by an IoC container.
When a class (ClassA
) needs to use another class (ClassB
), you can inject (pass
) the dependency into ClassA
, rather than having ClassA
create an instance of ClassB
internally.
Example
Without Dependency Injection:
public class ClassB
{
public int Calculate() => 100;
}
public class ClassA
{
private readonly ClassB _classB = new ClassB();
public int TenPercent()
{
return (int)(_classB.Calculate() * 0.1);
}
}
public class Program
{
public static void Main()
{
ClassA classA = new ClassA();
Console.WriteLine("Ten Percent: " + classA.TenPercent());
}
}
In this example, ClassA
creates its own instance of ClassB
, making it tightly coupled to ClassB
.
With Dependency Injection:
- Define Interfaces:
Create an interface IClassB
to abstract the dependency:
public interface IClassB
{
int Calculate();
}
- Implement the Interface:
Implement the interface in ClassB
:
public class ClassB : IClassB
{
public int Calculate() => 100;
}
- Inject Dependencies:
Modify ClassA
to accept an IClassB
instance through its constructor:
public class ClassA
{
private readonly IClassB _classB;
public ClassA(IClassB classB)
{
_classB = classB;
}
public int TenPercent()
{
return (int)(_classB.Calculate() * 0.1);
}
}
- Setup Dependency Injection:
In a real-world application, you use a DI container (like Microsoft.Extensions.DependencyInjection) to manage dependencies:
public class Program
{
public static void Main()
{
// Create a service collection and configure DI
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IClassB, ClassB>();
serviceCollection.AddTransient<ClassA>();
// Build the service provider
var serviceProvider = serviceCollection.BuildServiceProvider();
// Resolve and use the service
var classA = serviceProvider.GetService<ClassA>();
Console.WriteLine("Ten Percent: " + classA.TenPercent());
}
}
Benefits
-
Loose Coupling:
ClassA
is not dependent on a concrete implementation ofClassB
; it relies on theIClassB
interface. -
Reusability: You can easily switch
ClassB
with another implementation (e.g.,ClassC
) without changingClassA
. - Improved Testability: Mock dependencies can be injected for unit testing.
- Simpler Maintenance: Dependencies are managed centrally and can be easily updated or replaced.
- Concurrent Development: Teams can work on different components independently, as long as they adhere to the same interfaces.
- Better Design: Promotes separation of concerns and follows the SOLID principles.
This way, you get more flexible, maintainable, and testable code by applying Dependency Injection.
Top comments (0)