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