Поделиться через


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

Замечание

Это содержимое перепечатывается разрешением 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.

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

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

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

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

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

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

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

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

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

✔️ Бросайте System.InvalidCastException, если вызов оператора приведения приводит к преобразованию с потерями и контракт оператора не разрешает такие преобразования.

© Часть 2005, 2009 Корпорация Майкрософт. Все права защищены.

Перепечатан с разрешения Pearson Education, Inc. из Руководство по проектированию: Соглашения, идиомы и шаблоны для повторного использования библиотек .NET, 2-е издание Кшиштоф Чвалина и Брэд Абрамс, опубликованное 22 октября 2008 года Addison-Wesley Профессиональный в рамках серии разработки Microsoft Windows.

См. также