Неявные Операторы — Секрет Чистого Кода или Источник Ошибок?
Неявные операторы — мощная функция языка C#, которая позволяет сделать код более читаемым и выразительным. Они позволяют определять пользовательские преобразования, которые происходят без явного приведения, и, таким образом, устранять неуклюжий синтаксис.
Неявные операторы определяются с помощью ключевого слова
implicit и могут использоваться для создания метода, преобразующего один тип в другой:public readonly record struct MoneyЗдесь мы определили неявный оператор, который позволяет нам преобразовать значение double в объект Money и наоборот. Компилятор автоматически применяет оператор, когда это необходимо. Согласитесь, код использования выше выглядит проще и понятнее, чем
{
public decimal Amount { get; init; }
public static implicit operator Money(
decimal amount)
{
return new Money { Amount = amount };
}
public static implicit operator decimal(
Money money)
{
return money.Amount;
}
}
// Использование
Money money = 10.0m;
decimal amount = money;
Money m = new Money(10.0m);Неявные операторы позволяют создавать более выразительный и удобный для чтения код. Мы можем создавать типы, которые кажутся частью языка и естественным образом вписываются в предметную область, в которой вы работаете. Например, они прекрасно сочетаются со строго-типизированными идентификаторами.
decimal amount = m.Amount;
Два ключевых правила неявных операторов:
1. они не должны генерировать исключения,
2. они не должны терять информацию, поскольку преобразование выполняется автоматически компилятором.
Однако чрезмерное использование неявных операторов может привести к тому, что код будет труден для понимания и сопровождения. Одной из основных вещей, которых следует избегать, является создание неявных операторов, которые могут привести к потере данных или вызвать исключения. Поскольку неявные операторы применяются компилятором автоматически, любые исключения, которые они вызывают, может быть трудно отследить. Например, когда у нас возникает исключение InvalidCastException из-за неправильной операции преобразования типа, мы привыкли видеть строку кода с явной операцией приведения: мы видим в скобках тип, в который пытаемся преобразовать, применяемый к переменной или значению, и сразу знаем, что существует какая-то несовместимость, о чем свидетельствует исключение, указывающее на этот номер строки. С неявными операторами преобразование происходит «волшебным образом, под капотом». Поэтому, если в результате выполнения оператора возникает какая-либо ошибка, нам нужно не только сделать паузу, чтобы понять, что применяется неявный оператор (например, «Секундочку, как может double присваиваться к этому типу, который не является double?!»). Придётся также изучить код этого типа (будем надеяться, что у нас есть его исходный код!), а затем диагностировать, что не так с логикой.
Ещё одна вещь, которой следует избегать, — это создание неявных операторов, которые могут привести к неожиданному поведению. Код может быть легко читаемым, и это позволяет нам делать предположения о том, что происходит. Однако, если фактическое поведение не соответствует нашим ожиданиям, внезапно у нас возникает гораздо более серьёзная проблема, чем трудночитаемый код. Например, если вы создаёте неявный оператор, который преобразует строку в целое число. Может быть неясно, анализирует ли преобразование строку как число или просто получает длину строки. Удобочитаемость первостепенна. Если поведение не совпадает с тем, что читатель подразумевает, читая код, это создаст много путаницы.
Итого
Всегда следите за тем, чтобы ваши неявные операторы не вызывали исключений и не теряли информацию. И самое главное, убедитесь, что поведение ваших операторов соответствует тому, которое ожидает читатель от кода.
Источник: https://www.devleader.ca/2023/08/04/implicit-operators-clean-code-secrets-or-buggy-nightmare/