介面是對型別能力的標準化認證。IComparable 表示「我自己知道如何與同類比較」;IComparer 表示「我知道如何比較兩個物件」。這是策略模式在 .NET 框架中的經典應用:
IComparable,預設排序行為IComparer,支援多種排序規則、降序、多欄位排序等public interface IComparable { int CompareTo(object obj); }
public interface IComparable { int CompareTo(T other); }
回傳值:負數(小於)、零(等於)、正數(大於)。實作範例:
public class Student : IComparable
{
public string Name { get; set; }
public Scores Scores { get; set; }
public int CompareTo(Student other)
{
if (other == null) return 1;
return Name.CompareTo(other.Name); // 依姓名預設排序
}
}
// 使用
var students = new[] { new Student("Michale"), new Student("Jack"), ... };
Array.Sort(students); // 自動呼叫 CompareTo
public interface IComparer { int Compare(object x, object y); }
public interface IComparer { int Compare(T x, T y); }
優勢:
public class StudentComparer : IComparer
{
private readonly SubjectEnum _subject;
private readonly bool _descending;
public StudentComparer(SubjectEnum subject, bool descending)
{
_subject = subject;
_descending = descending;
}
public int Compare(Student x, Student y)
{
if (x == null && y == null) return 0;
if (x == null) return -1;
if (y == null) return 1;
int result = x.Scores[_subject].CompareTo(y.Scores[_subject]);
return _descending ? -result : result;
}
}
// 使用:依總分降序
Array.Sort(students, new StudentComparer(SubjectEnum.Total, true));
// 匿名委派 / Lambda 簡潔寫法
Array.Sort(students, (x, y) => x.Scores[SubjectEnum.Math].CompareTo(y.Scores[SubjectEnum.Math]));
// LINQ 風格(回傳新序列,不修改原陣列)
var sorted = students.OrderBy(s => s.Scores[SubjectEnum.English])
.ThenByDescending(s => s.Scores[SubjectEnum.Math]);
Comparison<T> 是 Func<T,T,int> 的別名,Array.Sort 與 List<T>.Sort 皆有多載接受它。
| 介面 | 適用場景 | 注意事項 |
|---|---|---|
| IComparable<T> | 型別有自然預設排序(如數值、日期、字串、編號) | 實作需滿足傳遞性、對稱性、自反性;處理 null 語意 |
| IComparer<T> | 多種排序規則、外部型別、需參數化比較 | 建議實作 IComparer<T> 而非非泛型版本;可序列化 |
| Comparison<T> | 一次性、簡單比較邏輯 | 無法攜帶狀態,複雜邏輯改用 IComparer |
掌握 IComparable(內建能力)與 IComparer(外部策略)的分工,能寫出既符合框架慣例又靈活擴充的排序程式碼。這也是介面導向設計「程式介面而非實作」的典範。