C#中可重载运算符包括一元的+、-、!、~、++、--、true、false,二元的+、-、*、/、%、&、|、^、、==、!=、、=,且==与!=等须成对重载;不可重载&&、||、?:、=等。

运算符重载在 C# 中只能在 struct 或 class 内部用 public static 方法实现,且必须使用 operator 关键字声明;不能重载所有运算符,也不能改变运算符优先级或结合性。
哪些运算符可以重载
C# 允许重载的运算符有明确限制。可重载的包括:
- 一元运算符:
+、-、!、~、++、--、true、false - 二元运算符:
+、-、*、/、%、&、|、^、、>>、==、!=、、>、、>= - 必须成对重载:
==和!=、和>、和>=、true和false
不可重载的包括:&&、||、?:、=、.、?:、->、sizeof、typeof、new、checked、unchecked 等。
重载 == 和 != 的正确写法
这是最容易出错的地方:重载 == 后,编译器会强制要求同时重载 !=,并且还必须重写 Equals(object) 和 GetHashCode(),否则会触发 CS0660 / CS0661 警告。
典型错误是只重载 ==,或在 == 中直接调用 object.ReferenceEquals 但没处理 null 参数。
public class Vector2
{
public double X { get; }
public double Y { get; }
public Vector2(double x, double y) => (X, Y) = (x, y);
public static bool operator ==(Vector2 a, Vector2 b)
{
if (ReferenceEquals(a, b)) return true;
if (a is null || b is null) return false;
return a.X == b.X && a.Y == b.Y;
}
public static bool operator !=(Vector2 a, Vector2 b) => !(a == b);
public override bool Equals(object obj) => obj is Vector2 v && this == v;
public override int GetHashCode() => HashCode.Combine(X, Y);}
重载 + 运算符并支持混合类型
如果希望 Vector2 + double 也能工作,不能只写 Vector2 + Vector2;需额外提供参数类型不同的重载版本。但要注意隐式转换可能引发歧义。
- 推荐显式提供
Vector2 + double和double + Vector2两个版本(后者因交换律必要) - 避免定义
implicit operator double(Vector2),否则vector + 1.0可能被误解释为(double)vector + 1.0 - 返回新实例而非修改原对象(符合值语义直觉)
public static Vector2 operator +(Vector2 a, Vector2 b) =>
new Vector2(a.X + b.X, a.Y + b.Y);
public static Vector2 operator +(Vector2 v, double s) =>
new Vector2(v.X + s, v.Y + s);
public static Vector2 operator +(double s, Vector2 v) =>
new Vector2(v.X + s, v.Y + s);
为什么重载 ++ 要返回新对象而不是 this
因为 ++ 是一元后缀/前缀运算符,C# 要求其返回值参与表达式计算。若返回 this 并修改内部状态,会导致与内置数值类型行为不一致(如 int 的 ++ 返回副本),也破坏不可变设计意图。
更关键的是:如果 ++ 修改自身又返回 this,则 v1 = v2++; 会让 v1 和 v2 引用同一对象,后续修改 v2 会意外影响 v1 —— 这在结构体中还会因装箱引发更隐蔽问题。
所以标准做法是:
- 前缀
++:创建新实例,返回新实例 - 后缀
++:先保存当前状态,再创建新实例,返回保存的旧状态
public static Vector2 operator ++(Vector2 v) => new Vector2(v.X + 1, v.Y + 1);// 后缀版本需手动模拟(C# 不自动区分,靠方法签名) public static Vector2 operator ++(ref Vector2 v) { var old = v; v = new Vector2(v.X + 1, v.Y + 1); return old; }
注意:C# 实际不支持 ref 形参用于运算符重载(上述写法非法),真正合规的后缀 ++ 必须返回旧值副本,且不能修改原对象 —— 所以多数场景下应避免重载 ++,改用明确的 Increment() 方法。










