在實作 System.IComparable.CompareTo 時,常見的簡寫寫法是直接回傳兩整數之差:
public int CompareTo(object rhs) {
Person other = (Person)rhs;
return this.age - other.age; // 看似簡潔,實則隱藏風險
}
邏輯上:差值為正表示 this > other,為零相等,為負表示 this < other。但這在邊界值時會發生溢位。
測試案例:
Person Lippman = new Person { age = int.MaxValue }; // 2,147,483,647
Person Richter = new Person { age = -1 };
int cmp = Lippman.CompareTo(Richter);
// 預期:Lippman > Richter,回傳正數
// 實際:cmp = -2,147,483,648(負數),判定 Lippman < Richter
原因:int.MaxValue - (-1) = 2,147,483,648 超出 int 範圍,溢位變為 int.MinValue(-2,147,483,648)。
checked {
return this.age - other.age;
}
編譯選項 /checked+ 亦可全域啟用。但拋出 OverflowException 並非比較器的預期行為。
if (this.age > other.age) return 1;
else if (this.age < other.age) return -1;
return 0;
或 .NET Framework 4.7+ 可用 Integer.Compare(this.age, other.age)。
若業務邏輯保證數值範圍(如年齡 0~150),可將欄位改為 short 或 ushort,相減不會溢位。但這屬於業務妥協,非通用解法。
此問題暴露「以減法代替比較」的本質風險:有號整數減法在極值時不保持序關係。C/C++ 中 qsort 比較函數同樣受此影響。標準庫實作(如 Java Integer.compare、.NET Comparer<int>.Default.Compare)均採用分支判斷而非減法。
Comparer<T>.Default.Compare、Integer.Compare 等。a > b ? 1 : (a < b ? -1 : 0) 模式。MinValue、MaxValue、零、正負邊界。「大師也有考慮不周到的地方」—— 這個經典錯誤提醒我們:看似等價的數學運算,在有限位元表示下可能語意大相逕庭。比較器關係到排序、查找、資料結構正確性,容不得半點馬虎。