Что означает время жизни Transient в DI-контейнере?

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

Ответ

Transient — это одно из основных времён жизни службы (Service Lifetime) в контейнере внедрения зависимостей (DI), например, в ASP.NET Core. При регистрации как Transient контейнер создаёт новый экземпляр службы каждый раз, когда она запрашивается.

Как зарегистрировать:

// В Startup.cs или Program.cs
services.AddTransient<IMyService, MyService>();
// Или для интерфейса
services.AddTransient<IEmailSender, SmtpEmailSender>();

Поведение на практике:

public class MyController : ControllerBase
{
    // Для каждого HTTP-запроса в этот контроллер
    // DI-контейнер создаст НОВЫЙ экземпляр MyService.
    private readonly IMyService _myService;
    public MyController(IMyService myService)
    {
        _myService = myService; // Новый экземпляр №1
    }
}

public class AnotherService
{
    // Если AnotherService также запросит IMyService,
    // он получит СОВЕРШЕННО ДРУГОЙ экземпляр.
    private readonly IMyService _anotherInstance;
    public AnotherService(IMyService myService)
    {
        _anotherInstance = myService; // Новый экземпляр №2
    }
}

Когда использовать Transient:

  • Служба не имеет состояния (stateless).
  • Служба лёгкая и её создание не нагружает систему (например, валидаторы, мапперы, простые хелперы).
  • Служба небезопасна для многопоточности и должна быть изолирована для каждого потребителя.
  • Служба зависит от других Transient или Scoped служб, которые не должны разделяться.

Потенциальные проблемы:

  • Производительность: Частое создание объектов может стать накладным, если служба "тяжёлая" (инициализирует подключения, загружает большие ресурсы).
  • Утечка памяти: Если служба реализует IDisposable, контейнер будет отслеживать и вызывать Dispose() для каждого созданного экземпляра, что при очень большом количестве созданий может привести к нагрузке на GC. В таких случаях стоит рассмотреть Scoped или Singleton lifetime.

Сравнение с другими временами жизни:

  • Scoped: Один экземпляр на область видимости (например, на HTTP-запрос).
  • Singleton: Один экземпляр на всё время работы приложения.