簡介
運算符重載是 C# 提供的一種特性,允許開發者為 自定義類型(類/結構體) 定義運算符的行為。
例如,可以讓 Vector 對象支持 + 運算,而不是僅限於基本類型(int、double 等)。
💡 本質:運算符重載是一個 帶有 operator 關鍵字的靜態方法,通過自定義方法改變運算符的操作行為。
適用範圍與限制
| 特性 | 説明 |
|---|---|
| 可重載的類型 | 類(class) 和 結構體(struct) |
| 不可重載的類型 | 接口、枚舉、委託 |
| 方法修飾符 | 必須是 public static |
| 至少一個自定義類型 | 運算符的參數中至少有一個必須是用户自定義類型 |
| 不能重載的運算符 | .(成員訪問)、?:(條件運算符)、new、is、as、typeof、sizeof、=, +=, -=(但可以間接重載) |
支持重載的運算符
| 分類 | 運算符 |
|---|---|
| 一元運算符 | + - ! ~ ++ -- true false |
| 二元運算符 | + - * / % & \` |
| 比較運算符 | == != < > <= >=(必須成對重載,如重載==則必須重載!=) |
| 轉換運算符 | implicit(隱式轉換) explicit(顯式轉換) |
基本語法
public static 返回類型 operator 運算符(參數列表)
{
// 自定義邏輯
}
operator關鍵字定義運算符。- 參數中至少有一個是當前類/結構體。
- 建議返回新的對象,保持不可變性。
常見示例
重載二元運算符(+)
創建一個二維向量類:
public struct Vector
{
public double X { get; }
public double Y { get; }
public Vector(double x, double y) => (X, Y) = (x, y);
public static Vector operator +(Vector a, Vector b)
=> new Vector(a.X + b.X, a.Y + b.Y);
public override string ToString() => $"({X}, {Y})";
}
// 使用
var v1 = new Vector(1, 2);
var v2 = new Vector(3, 4);
Console.WriteLine(v1 + v2); // 輸出: (4, 6)
重載一元運算符(-)
public static Vector operator -(Vector v)
=> new Vector(-v.X, -v.Y);
var v = new Vector(5, -3);
Console.WriteLine(-v); // 輸出: (-5, 3)
重載比較運算符(==, !=)
比較向量是否相等:
public static bool operator ==(Vector a, Vector b)
=> a.X == b.X && a.Y == b.Y;
public static bool operator !=(Vector a, Vector b)
=> !(a == b);
// 建議同時重寫 Equals 和 GetHashCode
public override bool Equals(object? obj)
=> obj is Vector v && this == v;
public override int GetHashCode()
=> HashCode.Combine(X, Y);
- 重載
==時 必須 同時重載!=。 Equals和GetHashCode也要同步實現,保證一致性。
重載遞增/遞減運算符(++/--)
public static Vector operator ++(Vector v)
=> new Vector(v.X + 1, v.Y + 1);
public static Vector operator --(Vector v)
=> new Vector(v.X - 1, v.Y - 1);
轉換運算符(implicit/explicit)
在 Vector 和 double 之間轉換:
public static implicit operator double(Vector v)
=> Math.Sqrt(v.X * v.X + v.Y * v.Y); // 隱式轉換為長度
public static explicit operator Vector(double d)
=> new Vector(d, d); // 需要強制轉換
使用:
Vector v = new Vector(3, 4);
double len = v; // 隱式轉換
Vector v2 = (Vector)5.0; // 顯式轉換
邏輯運算符(true/false)
用於自定義布爾邏輯:
public static bool operator true(Vector v) => v.X != 0 || v.Y != 0;
public static bool operator false(Vector v) => v.X == 0 && v.Y == 0;
Vector v = new Vector(0, 0);
if (v) // 自動調用 operator true
Console.WriteLine("非零向量");
else
Console.WriteLine("零向量");
運算符與方法的關係
運算符重載只是語法糖,編譯器會將運算符轉換為靜態方法調用:
var c = a + b;
// 等價於
var c = Vector.op_Addition(a, b);
常用方法映射:
| 運算符 | 生成的方法名 |
|---|---|
+ |
op_Addition |
- |
op_Subtraction |
* |
op_Multiply |
/ |
op_Division |
== |
op_Equality |
!= |
op_Inequality |
綜合示例:複數類
public struct Complex
{
public double Real { get; }
public double Imag { get; }
public Complex(double real, double imag)
=> (Real, Imag) = (real, imag);
public static Complex operator +(Complex a, Complex b)
=> new Complex(a.Real + b.Real, a.Imag + b.Imag);
public static Complex operator -(Complex a, Complex b)
=> new Complex(a.Real - b.Real, a.Imag - b.Imag);
public static Complex operator *(Complex a, Complex b)
=> new Complex(a.Real * b.Real - a.Imag * b.Imag,
a.Real * b.Imag + a.Imag * b.Real);
public static bool operator ==(Complex a, Complex b)
=> a.Real == b.Real && a.Imag == b.Imag;
public static bool operator !=(Complex a, Complex b)
=> !(a == b);
public override string ToString() => $"{Real} + {Imag}i";
}
總結
| 特性 | 説明 |
|---|---|
| 適用場景 | 數學計算類(向量、矩陣、複數)、日期時間、座標類 |
| 關鍵規則 | public static、至少一個參數為自定義類型 |
| 搭配使用 | Equals、GetHashCode、IComparable |
| 設計建議 | 遵循語義一致性、返回新對象、與方法重載保持協調 |