DI и IoC: зачем и как работает контейнер

↑ 3.2 Dependency Injection · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Базовый вопрос: «что такое DI, чем отличается от IoC и зачем контейнер». Дальше почти всегда идут времена жизни.

Объяснение

  • IoC (Inversion of Control) — принцип: не класс создаёт свои зависимости, а внешний код передаёт их.
  • DI (Dependency Injection) — способ реализации IoC: зависимости передаются через конструктор (предпочтительно), свойство или параметр метода.
  • DI-контейнер — инструмент, который по регистрациям строит граф объектов и управляет временем жизни.
// Без DI: жёсткая связь
public class OrderService { private readonly SqlRepo _repo = new SqlRepo(); }
 
// С DI: зависимость от абстракции
public class OrderService(IOrderRepository repo, ILogger<OrderService> log) { }
 
builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>();
builder.Services.AddScoped<OrderService>();
ВыгодаПояснение
Слабая связностьреализация заменяется без правки клиента
Тестируемостьподставляются fake/stub
Единое место сборкикомпозиционный корень в Program.cs
Управление временем жизниконтейнер создаёт и освобождает объекты

Как работает встроенный контейнер

ServiceProvider находит конструктор с максимальным числом разрешимых параметров, рекурсивно строит зависимости, кэширует экземпляры по времени жизни, вызывает Dispose у созданных им IDisposable при закрытии scope. Поддерживает open generics: AddScoped(typeof(IRepo<>), typeof(Repo<>)) и IEnumerable<T> для нескольких реализаций.

Нюансы и подводные камни

  • Constructor injection лучше property injection: зависимости явны и обязательны.
  • Service Locator (IServiceProvider.GetService в бизнес-коде) — антипаттерн, скрывает зависимости.
  • Много параметров конструктора — сигнал нарушения SRP.
  • Встроенный контейнер не умеет property injection, interceptors и автоматические декораторы (для этого Autofac/Scrutor).
  • Циклические зависимости приводят к исключению при построении.

Практика

  1. Уберите new из сервиса и зарегистрируйте зависимости.
  2. Зарегистрируйте несколько реализаций интерфейса и получите IEnumerable<T>.
  3. Напишите open generic репозиторий.

Вопросы с ответами

Связанные темы