运算符重载

注释

此内容由 Pearson Education, Inc. 的许可从 框架设计指南:可重用 .NET 库的约定、习惯和模式(第 2 版)重新打印。 该版于2008年出版,此后该书已于 第三版全面修订。 此页上的一些信息可能已过期。

运算符重载允许框架类型显示为内置语言基元。

尽管在某些情况下允许和有用,但应谨慎使用运算符重载。 在许多情况下,运算符重载被过度使用,比如说框架设计者开始将运算符用于应为简单方法的作用。 以下准则应帮助你确定何时以及如何使用运算符重载。

❌ 请避免定义运算符重载,除非在感觉像是基元(内置)类型的类型中。

✔️ 请考虑在某种类型中定义运算符重载,使其如同基元类型一般。

例如, System.String 具有 operator==operator!= 定义。

✔️ DO 在表示数字(如 System.Decimal)的结构中定义运算符重载。

❌ 定义运算符重载时不要使用花哨的手法。

操作符重载在操作结果显而易见的情况下非常有用。 例如,能够从一个DateTime减去另一个DateTime并得到TimeSpan是有意义的。 但是,以下操作是不恰当的:使用逻辑 union 运算符来联合两个数据库查询或使用 shift 运算符写入到流中。

❌ 除非至少有一个操作数属于定义重载的类型,否则请勿提供运算符重载。

✔️ 请确保以对称方式重载运算符。

例如,如果你重载了 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) 兼容。

转换运算符

转换运算符是一元运算符,允许从一种类型转换为另一种类型。 运算符必须定义为操作数或返回类型的静态成员。 有两种类型的转换运算符:隐式和显式。

❌ 如果最终用户未明确预期此类转换,请勿提供转换运算符。

❌ 请勿在类型域之外定义转换运算符。

例如,Int32DoubleDecimal都是数值类型,而DateTime不是。 因此,不应使用转换运算符将 a Double(long) 转换为 a DateTime。 在这种情况下,首选使用构造函数。

❌ 如果转换可能丢失,请勿提供隐式转换运算符。

例如,不应将Double隐式转换为Int32,因为Double的范围比Int32更大。 即使转换可能会有损失,也可以提供显式转换运算符。

❌ 请勿从隐式强制转换引发异常。

最终用户很难了解正在发生的事情,因为他们可能不知道正在发生转换。

✔️ 如果对强制转换运算符的调用导致有损转换,而该运算符的协定不允许有损转换,请务必引发 System.InvalidCastException

部分内容 © 2005, 2009 Microsoft 公司。 保留所有权利。

获得皮尔逊教育公司许可后重印自 框架设计准则:可重用 .NET 库的约定、习惯和模式 ,由 Krzysztof Cwalina 和 Brad Abrams 编写,并作为微软 Windows 开发系列中的出版物之一,于 2008 年 10 月 22 日由 Addison-Wesley Professional 出版。

另请参阅