Что такое DI-контейнер (контейнер внедрения зависимостей)?

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

Ответ

DI-контейнер (IoC-контейнер) — это библиотека или фреймворк, который автоматизирует процесс внедрения зависимостей. Вместо того чтобы вручную создавать объекты и передавать их зависимости (как в простом примере), вы регистрируете типы в контейнере, а он сам отвечает за создание экземпляров и разрешение всех цепочек зависимостей.

Основные функции DI-контейнера:

  • Регистрация (Registration): Указание, какой класс соответствует какому интерфейсу и как управлять его жизненным циклом.
  • Разрешение (Resolution): Автоматическое создание запрошенного объекта со всеми его зависимостями.
  • Управление жизненным циклом (Lifetime Management): Контроль над тем, как долго "живет" экземпляр сервиса.

Пример использования встроенного контейнера .NET:

using Microsoft.Extensions.DependencyInjection;

// Создаем коллекцию сервисов
var services = new ServiceCollection();

// Регистрируем зависимости с указанием времени жизни
services.AddTransient<ILogger, ConsoleLogger>(); // Новый экземпляр при каждом запросе
services.AddScoped<IOrderRepository, SqlOrderRepository>(); // Один экземпляр на область (scope), например, на HTTP-запрос
services.AddSingleton<ICacheService, MemoryCacheService>(); // Один экземпляр на все время работы приложения

// Регистрируем наш основной сервис
services.AddTransient<OrderProcessor>();

// Строим провайдер (контейнер)
var serviceProvider = services.BuildServiceProvider();

// Запрашиваем сервис. Контейнер автоматически создаст OrderProcessor,
// внедрит в него ILogger и IOrderRepository, создав их при необходимости.
using (var scope = serviceProvider.CreateScope())
{
    var processor = scope.ServiceProvider.GetRequiredService<OrderProcessor>();
    processor.ProcessOrder(new Order());
}

Популярные контейнеры для .NET: Autofac, Ninject, Simple Injector, Unity. ASP.NET Core по умолчанию использует легковесный, но функциональный контейнер Microsoft.Extensions.DependencyInjection.

Зачем он нужен? Контейнер избавляет от необходимости писать сложный "проводочный" код (wire-up code) для создания графа объектов, особенно в больших приложениях с глубокими цепочками зависимостей.