Перегрузки операторов

Примечание.

Это содержимое перепечатывается разрешением Pearson Education, Inc. из руководства по проектированию платформы: соглашения, идиомы и шаблоны для повторно используемых библиотек .NET, 2-го выпуска. Этот выпуск был опубликован в 2008 году, и книга с тех пор была полностью пересмотрена в третьем выпуске. Некоторые сведения на этой странице могут быть устаревшими.

Перегрузки операторов позволяют отображать типы платформ, как встроенные примитивы языка.

Хотя в некоторых ситуациях это разрешено и полезно, перегрузки операторов следует использовать осторожно. Существует множество случаев злоупотреблений перегрузкой операторов. Например, когда конструкторы платформы использовали операторы для операций, которые должны быть простыми методами. Следующие рекомендации помогут решить, когда и как использовать перегрузку операторов.

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

✔️ РЕКОМЕНДУЕТСЯ определять перегрузки операторов в типе, который должен быть похож на примитивный тип.

Например, в System.String определены operator== и operator!=.

✔️ РЕКОМЕНДУЕТСЯ️ определить перегрузки операторов в структурах, которые представляют числа (например, System.Decimal).

❌ ОТНЕСИТЕСЬ к определению перегрузки операторов серьезно.

Перегрузка операторов полезна в случаях, когда сразу очевидно, каким будет результат операции. Например, есть смысл вычесть одно значение DateTime из другого DateTime и получить TimeSpan. Однако не рекомендуется использовать оператор логического объединения, чтобы объединить два запроса к базе данных или использовать оператор сдвига для записи в поток.

❌ НЕ следует предоставлять перегрузки операторов, если по крайней мере один из операндов не относится к типу, определяющему перегрузку.

✔️ ВЫПОЛНЯЙТЕ операторы перегрузки в симметричном режиме.

Например, если перегрузить operator==, необходимо также перегрузить operator!=. Аналогично если перегрузить operator<, то необходимо также перегрузить operator> и т. д.

✔️️ ПОДБЕРИТЕ методы с понятными именами, которые соответствуют каждому перегруженному оператору.

Многие языки не поддерживают перегрузку операторов. По этой причине рекомендуется, чтобы типы с перегруженными операторами, включали дополнительный метод с соответствующим доменным именем, обеспечивающим эквивалентную функциональность.

В следующей таблице приведен список операторов и соответствующие понятные имена методов.

Символ оператора C# Имя метаданных Понятное имя
N/A op_Implicit To<TypeName>/From<TypeName>
N/A op_Explicit To<TypeName>/From<TypeName>
+ (binary) op_Addition Add
- (binary) op_Subtraction Subtract
* (binary) op_Multiply Multiply
/ op_Division Divide
% op_Modulus Mod or Remainder
^ op_ExclusiveOr Xor
& (binary) op_BitwiseAnd BitwiseAnd
| op_BitwiseOr BitwiseOr
&& op_LogicalAnd And
|| op_LogicalOr Or
= op_Assign Assign
<< op_LeftShift LeftShift
>> op_RightShift RightShift
N/A op_SignedRightShift SignedRightShift
N/A op_UnsignedRightShift UnsignedRightShift
== op_Equality Equals
!= op_Inequality Equals
> op_GreaterThan CompareTo
< op_LessThan CompareTo
>= op_GreaterThanOrEqual CompareTo
<= op_LessThanOrEqual CompareTo
*= op_MultiplicationAssignment Multiply
-= op_SubtractionAssignment Subtract
^= op_ExclusiveOrAssignment Xor
<<= op_LeftShiftAssignment LeftShift
%= op_ModulusAssignment Mod
+= op_AdditionAssignment Add
&= op_BitwiseAndAssignment BitwiseAnd
|= op_BitwiseOrAssignment BitwiseOr
, op_Comma Comma
/= op_DivisionAssignment Divide
-- op_Decrement Decrement
++ op_Increment Increment
- (unary) op_UnaryNegation Negate
+ (unary) op_UnaryPlus Plus
~ op_OnesComplement OnesComplement

Перегрузка оператора равенства ==

Перегрузка operator == довольно сложная. Семантика оператора должна быть совместима с несколькими другими элементами, например Object.Equals.

Операторы преобразования

Операторы преобразования — это унарные операторы, позволяющие выполнять преобразование из одного типа в другой. Операторы должны быть определены как статические элементы либо как операнды или типы возвращаемого значения. Существует два типа операторов преобразования: implicit и explicit.

❌ НЕ предоставляйте оператор преобразования, если пользователь явно не ожидает такое преобразование.

❌ НЕ определяйте операторы преобразования за пределами домена типа.

Например, Int32, Double и Decimal являются числовыми типами, а DateTime — нет. Поэтому при преобразовании Double(long) в DateTime не должен использоваться оператор преобразования. В таком случае предпочтительнее использовать конструктор.

❌ НЕ предоставляйте неявный оператор преобразования, если преобразование может быть с потерями.

Например, не существует неявного преобразования из Double в Int32, так как Doubleимеет более широкий диапазон, чем Int32. Явный оператор преобразования можно предоставить даже в том случае, если преобразование может быть с потерями.

❌ НЕ создавайте исключения из неявных приведений.

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

✔️ РЕКОМЕНДУЕТСЯ создать System.InvalidCastException, если вызов оператора приведения приводит к преобразованию с потерями, а контракт оператора не допускает этого.

Фрагменты: © Корпорация Майкрософт (Microsoft Corporation), 2005, 2009. Все права защищены.

Перепечатано с разрешения Pearson Education, Inc. из книги Инфраструктура программных проектов. Соглашения, идиомы и шаблоны для многократно используемых библиотек .NET (2-е издание), авторы: Кржиштоф Цвалина (Krzysztof Cwalina) и Брэд Абрамс (Brad Abrams). Книга опубликована 22 октября 2008 г. издательством Addison-Wesley Professional в рамках серии, посвященной разработке для Microsoft Windows.

См. также