TG Telegram Group & Channel
.NET Разработчик | United States America (US)
Create: Update:

День 1777. #ЗаметкиНаПолях
Где Имеет Смысл Применять Первичные Конструкторы
Первичные конструкторы классов появились в C# 12. Один из первых вопросов, который может возникнуть: как они работают и какова область их применения?

Во-первых, параметры первичных конструкторов ведут себя как параметры метода или обычного конструктора. Т.е. к этому параметру можно получить доступ и изменить его, как и любой другой параметр, из любого места внутри класса. Например:

public class Customer(string name)
{
// выдаст предупреждение компилятора
public string Name { get; } = name;

public string FullName => name;
public void Format() => name = name.ToUpper();
}

var c = new Customer("steve");
c.Format();
Console.WriteLine(c.Name); // steve
Console.WriteLine(c.FullName); // STEVE

После того, как вы вызовете метод Format(), все ссылки на name будут использовать изменённую версию name, поскольку параметр изменяемый. Т.е., если вы собираетесь использовать первичные конструкторы для внедрения зависимостей, любой оператор внутри принимающего класса может изменить значение параметра. По сути, вы не можете доверять тому, что значение параметра соответствует тому, что было передано.

Валидация
Как правило, рекомендуется проверять аргументы конструктора. Типичное место проверки входных данных — конструктор с использованием защитных предложений.
Примечание: я не нашёл, как можно проверять собственно параметры первичного конструктора. Поэтому подозреваю, что это придётся делать при каждом использовании, например:
public class Customer(string name)
{
public string Name
{
get
{
ArgumentException
.ThrowIfNullOrEmpty(nameof(name));
return name;
}
}
}

Если вы знаете другой способ (исключая сторонние библиотеки), пожалуйста, напишите в комментариях.

Внедрение зависимостей
Вы можете использовать первичные конструкторы для зависимостей, как и обычный конструктор:
public class MyService(
IMyRepo _repo,
ILogger<MyService> _logger)
{

}

В небольшом простом классе сервиса может быть приемлемо использовать аргументы первичного конструктора. Однако это быстро может перерасти в проблему.

Во-первых, как упоминалось выше, параметры первичных конструкторов изменяемы. То есть любой метод может изменить их, и тогда полагаться на их значение будет нельзя. Вы не можете пометить их как только для чтения. Пока для этого недостаточно поддержки на уровне языка.

Во-вторых, по мере роста объёма кода класса становится неочевидно, откуда берутся параметры класса. Они называются как закрытые поля полями (с префиксом _), но ими не являются. Если вы попытаетесь получить к ним доступ через this, это не сработает.

DTO
Конечно, это будет работать. Но вам всё равно захочется назначить их свойствам. Однако в этом случае проще использовать запись, которая даст и неизменяемость, и переопределённый ToString, и прочие преимущества.

Итого
Учитывая текущую реализацию первичных конструкторов классов C#:
- Используйте аргументы первичного конструктора только для инициализации полей и свойств. Избегайте доступа к ним где-либо ещё (за исключением, возможно, тривиальных реализаций классов).
- Учитывая, что это параметры, их лучше называть, как и обычные параметры с помощью camelCase, без префикса _.
- До тех пор, пока не будут доступны дополнительные ограничения для параметров первичного конструктора, они представляют собой ружьё, которым разработчики могут отстрелить себе …, если не будут осторожны. Обязательно включите TreatWarningsAsErrors, чтобы отслеживать любые случаи, когда вы ссылаетесь на параметры уровня класса, помимо инициализации (особенно предупреждение CS9124).

Источник: https://blog.nimblepros.com/blogs/where-csharp-primary-constructors-make-sense/

День 1777. #ЗаметкиНаПолях
Где Имеет Смысл Применять Первичные Конструкторы
Первичные конструкторы классов появились в C# 12. Один из первых вопросов, который может возникнуть: как они работают и какова область их применения?

Во-первых, параметры первичных конструкторов ведут себя как параметры метода или обычного конструктора. Т.е. к этому параметру можно получить доступ и изменить его, как и любой другой параметр, из любого места внутри класса. Например:
public class Customer(string name)
{
// выдаст предупреждение компилятора
public string Name { get; } = name;

public string FullName => name;
public void Format() => name = name.ToUpper();
}

var c = new Customer("steve");
c.Format();
Console.WriteLine(c.Name); // steve
Console.WriteLine(c.FullName); // STEVE

После того, как вы вызовете метод Format(), все ссылки на name будут использовать изменённую версию name, поскольку параметр изменяемый. Т.е., если вы собираетесь использовать первичные конструкторы для внедрения зависимостей, любой оператор внутри принимающего класса может изменить значение параметра. По сути, вы не можете доверять тому, что значение параметра соответствует тому, что было передано.

Валидация
Как правило, рекомендуется проверять аргументы конструктора. Типичное место проверки входных данных — конструктор с использованием защитных предложений.
Примечание: я не нашёл, как можно проверять собственно параметры первичного конструктора. Поэтому подозреваю, что это придётся делать при каждом использовании, например:
public class Customer(string name)
{
public string Name
{
get
{
ArgumentException
.ThrowIfNullOrEmpty(nameof(name));
return name;
}
}
}

Если вы знаете другой способ (исключая сторонние библиотеки), пожалуйста, напишите в комментариях.

Внедрение зависимостей
Вы можете использовать первичные конструкторы для зависимостей, как и обычный конструктор:
public class MyService(
IMyRepo _repo,
ILogger<MyService> _logger)
{

}

В небольшом простом классе сервиса может быть приемлемо использовать аргументы первичного конструктора. Однако это быстро может перерасти в проблему.

Во-первых, как упоминалось выше, параметры первичных конструкторов изменяемы. То есть любой метод может изменить их, и тогда полагаться на их значение будет нельзя. Вы не можете пометить их как только для чтения. Пока для этого недостаточно поддержки на уровне языка.

Во-вторых, по мере роста объёма кода класса становится неочевидно, откуда берутся параметры класса. Они называются как закрытые поля полями (с префиксом _), но ими не являются. Если вы попытаетесь получить к ним доступ через this, это не сработает.

DTO
Конечно, это будет работать. Но вам всё равно захочется назначить их свойствам. Однако в этом случае проще использовать запись, которая даст и неизменяемость, и переопределённый ToString, и прочие преимущества.

Итого
Учитывая текущую реализацию первичных конструкторов классов C#:
- Используйте аргументы первичного конструктора только для инициализации полей и свойств. Избегайте доступа к ним где-либо ещё (за исключением, возможно, тривиальных реализаций классов).
- Учитывая, что это параметры, их лучше называть, как и обычные параметры с помощью camelCase, без префикса _.
- До тех пор, пока не будут доступны дополнительные ограничения для параметров первичного конструктора, они представляют собой ружьё, которым разработчики могут отстрелить себе …, если не будут осторожны. Обязательно включите TreatWarningsAsErrors, чтобы отслеживать любые случаи, когда вы ссылаетесь на параметры уровня класса, помимо инициализации (особенно предупреждение CS9124).

Источник: https://blog.nimblepros.com/blogs/where-csharp-primary-constructors-make-sense/
👍14


>>Click here to continue<<

.NET Разработчик




Share with your best friend
VIEW MORE

United States America Popular Telegram Group (US)