Dependency Injection is a design pattern in software development that allows you to create more modular and testable code by separating the construction and wiring of objects from their use. Instead of an object creating and managing its own dependencies, these dependencies are passed into the object from an external source. This external source is often called a dependency injection container or framework.

In C#, dependency injection can be implemented using various frameworks like Autofac, Ninject, Unity, and Microsoft.Extensions.DependencyInjection. Here is an example of how to use the built-in Microsoft.Extensions.DependencyInjection framework:

1. Define the interface and implementation of the dependency:

“`csharp
public interface INotificationService
{
void SendNotification(string message);
}

public class EmailNotificationService : INotificationService
{
public void SendNotification(string message)
{
// Implementation to send notification via email
}
}
“`

2. Configure the dependency injection container:

“`csharp
var serviceProvider = new ServiceCollection()
.AddSingleton()
.BuildServiceProvider();
“`

3. Use the dependency in a class:

“`csharp
public class NotificationManager
{
private readonly INotificationService _notificationService;

public NotificationManager(INotificationService notificationService)
{
_notificationService = notificationService;
}

public void NotifyUsers()
{
// Use the notification service to send notifications
_notificationService.SendNotification(“Notification message”);
}
}
“`

4. Resolve and use the class with its dependencies:

“`csharp
var notificationManager = serviceProvider.GetService();
notificationManager.NotifyUsers();
“`

In this example, the `NotificationManager` class depends on the `INotificationService` interface. When an instance of `NotificationManager` is created, the dependency injection container automatically resolves and injects an instance of `EmailNotificationService` into it.

By using dependency injection, the `NotificationManager` class is no longer responsible for creating and managing the `INotificationService` dependency, which makes the code more modular, testable, and maintainable. It also allows for easier swapping of implementations, such as using a different notification service for testing purposes.