Что такое Dependency Injection (DI) в C#?

«Что такое Dependency Injection (DI) в C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Dependency Injection (DI) — это паттерн проектирования, при котором зависимости объекта (сервисы, которые он использует) предоставляются ему извне, а не создаются внутри самого объекта. Это делает код слабосвязанным, тестируемым и легким для поддержки.

Основные типы внедрения зависимостей:

  1. Внедрение через конструктор (Constructor Injection) — самый распространенный и рекомендуемый способ.
  2. Внедрение через свойство (Property Injection).
  3. Внедрение через метод (Method Injection).

Пример Constructor Injection:

// 1. Интерфейс зависимости
public interface ILogger
{
    void Log(string message);
}

// 2. Конкретная реализация
public class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"[LOG]: {message}");
}

// 3. Класс, который зависит от ILogger. Зависимость внедряется через конструктор.
public class OrderProcessor
{
    private readonly ILogger _logger;

    // Конструктор получает зависимость извне
    public OrderProcessor(ILogger logger)
    {
        _logger = logger; // Внедрение зависимости
    }

    public void ProcessOrder(Order order)
    {
        // Бизнес-логика...
        _logger.Log("Order processed successfully.");
    }
}

// 4. Использование (обычно конфигурируется в DI-контейнере)
ILogger logger = new ConsoleLogger();
var processor = new OrderProcessor(logger); // Зависимость "внедрена"
processor.ProcessOrder(new Order());

Преимущества DI:

  • Слабая связность: Классы не зависят от конкретных реализаций, а только от абстракций (интерфейсов).
  • Упрощенное тестирование: Легко подменить реальную зависимость (например, доступ к базе данных) на mock-объект в юнит-тестах.
  • Гибкость и поддерживаемость: Изменение реализации зависимости (например, замена логгера) требует правок только в одном месте — конфигурации DI-контейнера.

В экосистеме .NET DI является фундаментальной частью ASP.NET Core и реализуется через встроенный контейнер (Microsoft.Extensions.DependencyInjection) или сторонние библиотеки (Autofac, Ninject).