Implementing Dependency Injection in C#: Building Loosely Coupled and Testable Applications
Learn the principles and techniques of dependency injection (DI) in C#. This tutorial explains different DI approaches—constructor injection, property injection, and method injection—and demonstrates their application in creating more modular, testable, and maintainable C# applications.
Dependency Injection in C#
Dependency Injection (DI) is a design pattern that promotes loose coupling in your code. Instead of a class creating its own dependencies, they are provided from the outside (injected). This improves code organization, testability, and maintainability.
Types of Dependency Injection in C#
C# supports three main types of dependency injection:
- Constructor Injection
- Property Injection
- Method Injection
1. Constructor Injection
Dependencies are provided through a class's constructor. This ensures that all required dependencies are available when the object is created. It promotes better testability and encapsulation.
public interface IEmailService { void SendEmail(string to, string subject, string body); }
public class EmailService : IEmailService { public void SendEmail(string to, string subject, string body) { ... } }
public class NotificationService {
private readonly IEmailService _emailService;
public NotificationService(IEmailService emailService) { _emailService = emailService; }
// ...
}
2. Property Injection
Dependencies are provided through public properties. This allows you to set dependencies after an object is created, offering more flexibility than constructor injection.
public interface ILogger { void Log(string message); }
public class ConsoleLogger : ILogger { public void Log(string message) { ... } }
public class MyClass {
public ILogger Logger { get; set; }
public void MyMethod() { Logger.Log("Something happened!"); }
}
3. Method Injection
Dependencies are passed as parameters to a method. This provides fine-grained control; you inject dependencies only when a method is called, rather than when the entire object is created.
public class MyClass {
public void MyMethod(ILogger logger) {
logger.Log("Something happened!");
}
}