Przeciążenia operatorów
Uwaga
Ta zawartość jest drukowana przez uprawnienie Pearson Education, Inc. z Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition. Wydanie to zostało opublikowane w 2008 roku, a książka została w pełni zmieniona w trzecim wydaniu. Niektóre informacje na tej stronie mogą być nieaktualne.
Przeciążenia operatorów umożliwiają pojawienie się typów struktur tak, jakby były wbudowanymi elementami pierwotnymi języka.
Mimo że dozwolone i przydatne w niektórych sytuacjach, przeciążenia operatorów powinny być używane ostrożnie. Istnieje wiele przypadków, w których przeciążenie operatora zostało nadużywane, na przykład gdy projektanci struktur zaczęli używać operatorów do operacji, które powinny być prostymi metodami. Poniższe wskazówki powinny pomóc w podjęciu decyzji o tym, kiedy i jak używać przeciążenia operatora.
❌ UNIKAJ definiowania przeciążeń operatorów, z wyjątkiem typów, które powinny wyglądać jak typy pierwotne (wbudowane).
✔️ ROZWAŻ zdefiniowanie przeciążeń operatorów w typie, który powinien wyglądać jak typ pierwotny.
Na przykład System.String ma operator==
i operator!=
zdefiniowano.
✔️ Do define operator przeciążenia w strukturach reprezentujących liczby (na przykład System.Decimal).
❌ Nie należy stosować cięć podczas definiowania przeciążeń operatorów.
Przeciążenie operatora jest przydatne w przypadkach, w których natychmiast jest oczywiste, jaki będzie wynik operacji. Na przykład warto odjąć jeden DateTime od innego DateTime
i uzyskać wartość TimeSpan. Jednak nie jest właściwe użycie operatora unii logicznej do utworzenia dwóch zapytań bazy danych lub użycie operatora shift do zapisu w strumieniu.
❌ NIE należy dostarczać przeciążeń operatorów, chyba że co najmniej jeden z operandów jest typu definiującego przeciążenie.
✔️ Operatory przeciążenia DO w sposób symetryczny.
Jeśli na przykład przeciążysz element operator==
, należy również przeciążyć element operator!=
. Podobnie, jeśli przeciążysz operator<
element , należy również przeciążyć operator>
element i tak dalej.
✔️ ROZWAŻ podanie metod z przyjaznymi nazwami odpowiadającymi każdemu przeciążonemu operatorowi.
Wiele języków nie obsługuje przeciążenia operatora. Z tego powodu zaleca się, aby typy, które przeciążyły operatory, obejmują metodę pomocniczą z odpowiednią nazwą specyficzną dla domeny, która zapewnia równoważne funkcje.
Poniższa tabela zawiera listę operatorów i odpowiednie przyjazne nazwy metod.
Symbol operatora języka C# | Nazwa metadanych | Przyjazna nazwa |
---|---|---|
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 przeciążenia ==
Przeciążenie operator ==
jest dość skomplikowane. Semantyka operatora musi być zgodna z kilkoma innymi elementami członkowskimi, takimi jak Object.Equals.
Operatory konwersji
Operatory konwersji to operatory jednoargumentowe, które umożliwiają konwersję z jednego typu na inny. Operatory muszą być zdefiniowane jako statyczne elementy członkowskie w operand lub zwracany typ. Istnieją dwa typy operatorów konwersji: niejawne i jawne.
❌ Nie udostępniaj operatora konwersji, jeśli taka konwersja nie jest wyraźnie oczekiwana przez użytkowników końcowych.
❌ NIE należy definiować operatorów konwersji poza domeną typu.
Na przykład , Int32Doublei Decimal są wszystkimi typami liczbowymi, natomiast DateTime nie jest. W związku z tym nie powinien istnieć operator konwersji, aby przekonwertować Double(long)
element na DateTime
. Konstruktor jest preferowany w takim przypadku.
❌ Nie należy podawać niejawnego operatora konwersji, jeśli konwersja jest potencjalnie strata.
Na przykład nie powinno istnieć niejawna konwersja z Double
do Int32
, ponieważ Double
ma szerszy zakres niż Int32
. Można podać jawny operator konwersji, nawet jeśli konwersja jest potencjalnie strata.
❌ NIE zgłaszaj wyjątków od niejawnych rzutów.
Użytkownikom końcowym bardzo trudno jest zrozumieć, co się dzieje, ponieważ mogą nie być świadomi, że odbywa się konwersja.
✔️ Wyrzuć, System.InvalidCastException jeśli wywołanie operatora rzutowania powoduje utratę konwersji, a kontrakt operatora nie zezwala na konwersje strat.
© Części 2005, 2009 Microsoft Corporation. Wszelkie prawa zastrzeżone.
Reprinted by permission of Pearson Education, Inc. from Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition by Krzysztof Cwalina and Brad Abrams, published oct 22, 2008 by Addison-Wesley Professional w ramach Microsoft Windows Development Series.