注
このコンテンツは、 フレームワーク設計ガイドライン (再利用可能な .NET ライブラリの規則、イディオム、パターン、第 2 版) から、Pearson Education, Inc. のアクセス許可によって再印刷されます。 そのエディションは2008年に出版され、その後 、本は第3版で完全に改訂されています。 このページの情報の一部が古くなっている可能性があります。
演算子のオーバーロードを使用すると、フレームワーク型を組み込みの言語プリミティブのように表示できます。
一部の状況では許可され便利ですが、演算子のオーバーロードは慎重に使用する必要があります。 フレームワーク デザイナーが単純なメソッドである必要がある操作に演算子を使用し始めた場合など、演算子のオーバーロードが悪用されたケースは多数あります。 次のガイドラインは、演算子のオーバーロードを使用するタイミングと方法を決定するのに役立ちます。
❌ プリミティブ (組み込み) 型のように感じる必要がある型を除き、演算子オーバーロードの定義は避けてください。
✔️ プリミティブ型のように感じる型で演算子オーバーロードを定義することを検討してください。
たとえば、 System.String には operator==
と operator!=
が定義されています。
✔️ DO は、数値 ( System.Decimal など) を表す構造体の演算子オーバーロードを定義します。
❌ 演算子のオーバーロードを定義するときは、かわいいしないでください。
演算子のオーバーロードは、操作の結果が何であるかをすぐに明らかにする場合に役立ちます。 たとえば、ある DateTime を別の DateTime
から減算し、 TimeSpanを取得することは理にかなっています。 ただし、論理和集合演算子を使用して 2 つのデータベース クエリを結合したり、シフト演算子を使用してストリームに書き込んだりすることは適切ではありません。
❌ オペランドの少なくとも 1 つがオーバーロードを定義する型でない限り、演算子オーバーロードを提供しないでください。
✔️ DO 演算子を対称的にオーバーロードします。
たとえば、 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 == のオーバーロード
operator ==
のオーバーロードは非常に複雑です。 演算子のセマンティクスは、 Object.Equalsなど、他のいくつかのメンバーと互換性がある必要があります。
変換演算子
変換演算子は、ある型から別の型への変換を可能にする単項演算子です。 演算子は、オペランドまたは戻り値の型の静的メンバーとして定義する必要があります。 変換演算子には、暗黙的と明示的の 2 種類があります。
❌ エンド ユーザーがこのような変換を明確に想定していない場合は、変換演算子を指定しないでください。
❌ 型のドメインの外部で変換演算子を定義しないでください。
たとえば、 Int32、 Double、 Decimal はすべて数値型ですが、 DateTime は数値型ではありません。 そのため、 Double(long)
を DateTime
に変換する変換演算子は必要ありません。 このような場合は、コンストラクターを使用することをお勧めします。
❌ 変換が損失の可能性がある場合は、暗黙的な変換演算子を指定しないでください。
たとえば、Double
はInt32
よりも範囲が広いため、Double
からInt32
への暗黙的な変換は必要ありません。 変換が損失の可能性がある場合でも、明示的な変換演算子を指定できます。
❌ 暗黙のキャストから例外をスローしないでください。
エンド ユーザーが何が起こっているのかを理解するのは非常に困難です。変換が行われているとは認識していない可能性があるためです。
✔️ キャスト演算子の呼び出しによって損失を伴う変換が発生し、演算子のコントラクトでは損失を伴う変換が許可されていない場合は、System.InvalidCastException をスローします。
Portions © 2005, 2009 Microsoft Corporation. 無断転載を禁じます。
フレームワーク設計ガイドライン:再利用可能な .NET ライブラリの規則、イディオム、パターン、Krzysztof Cwalina および Brad Abrams による第 2 版は、2008 年 10 月 22 日に Microsoft Windows 開発シリーズの一部として Addison-Wesley Professional によって公開されました。