TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #3167 1.71K
День 2640. #ЗаметкиНаПолях
Первичные Конструкторы для Внедрения Зависимостей. Окончание

Начало

Ловушка, которая отталкивает многих
Параметры первичного конструктора не являются полями только для чтения. Когда вы используете параметр первичного конструктора непосредственно в теле класса (как мы делали в классе сервиса), компилятор захватывает его как изменяемую переменную. За кулисами не генерируется поля только для чтения.

Т.е. вы можете изменить значение параметра:
public class OrderService(
IOrderRepository repo,
ILogger<OrderService> logger)
{
// …

public void SomeOtherMethod()
{
repo = null!;
logger = null!;
}
}

Этот код компилируется без ошибок и предупреждений. Если вам необходимы гарантии неизменяемости, явно присвойте параметр полю только для чтения:
public class OrderService(
IOrderRepository repo,
ILogger<OrderService> logger)
{
private readonly IOrderRepository _repo = repo;
private readonly ILogger<OrderService> _logger = logger;

// …
}

Но теперь мы потеряли большую часть преимуществ первичных конструкторов. Мы вернулись к объявлениям полей и присваиваниям, только с другим синтаксисом.

На практике вряд ли вы столкнётесь с этой проблемой в классе сервиса, получаемого из DI. Маловероятно, что вы случайно измените значение logger посреди метода. Но это может создать проблемы в классах сущностей или объектов-значений, где неизменяемость действительно важна. Это единственное место, где по-прежнему стоит проявлять осторожность.

Где использовать традиционные конструкторы
Вот случаи, когда стоит придерживаться традиционного подхода:

1. Сложная логика валидации
Если нужно проверять параметры перед их присваиванием, понадобится тело конструктора:
public class EmailAddress
{
private readonly string _value;

public EmailAddress(string value)
{
if (string.IsNullOrWhiteSpace(value)
|| !value.Contains('@'))
throw new ArgumentException(
"Неверный email.", nameof(value));

_value = value;
}
}

Первичные конструкторы не позволяют разместить логику валидации до выполнения тела класса.

2. Множественные перегрузки конструкторов
Первичные конструкторы поддерживают одну сигнатуру конструктора. Если вам нужны перегрузки, придётся связывать обычные конструкторы с помощью this(…), что быстро приводит к беспорядку.

3. Слишком много параметров
Как только вы достигнете 5 и более зависимостей, строка первичного конструктора станет трудночитаемой. Хотя, тогда класс, вероятно, будет иметь слишком много обязанностей, и рефакторинг будет лучшим решением, чем ухищрения с форматированием.

Итого
- Можно использовать первичные конструкторы для всех классов сервисов в DI. Экономия на шаблонном коде того стоит.
- Они полезны для создания сущностей, когда вы хотите обеспечить обязательность параметров на уровне типа.
- Параметры основного конструктора сохраняются как изменяемые переменные, а не поля только для чтения. Это единственное, о чём нужно помнить. Эта изменяемость не страшна в классах сервисов, потому что в этом контексте это вряд ли вызовет реальные ошибки.
- Стоит придерживаться традиционных конструкторов для типов с валидацией, множественными перегрузками или со слишком большим количеством зависимостей.

Переход того стоит. Классы сервисов короче, их проще сканировать, а ловушка изменяемости не так уж страшна.

Источник: https://www.milanjovanovic.tech/blog/why-i-switched-to-primary-constructors-for-di-in-csharp
  • 👍 4
More from @netdeveloperdiary
  1. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  2. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  3. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
  4. Sep 24, 2026День 2794. #Оффтоп #Здоровье Сегодня будет необычный пост. Завтра в Москве стартует конфер…
  5. Sep 23, 2026День 2793. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  6. Sep 22, 2026День 2792. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →