繼上一篇介紹基本 IComparable<T> 實作後,本文深入探討當單一類別需要支援多種排序規則時,如何透過實作 IComparer<T> 介面實現靈活的排序策略切換。
List<T>.Sort() 預設會呼叫元素實作的 IComparable<T>.CompareTo() 進行快速排序。但當我們需要「同一組資料、不同排序邏輯」時(如員工既可按工號排序,也可按工齡排序),單一 CompareTo 方法無法滿足需求。此時應建立實作 IComparer<T> 的比較器類別,並傳遞給 Sort(IComparer<T>) 多載方法。
public enum ComparisonType
{
EmpID, // 依員工編號
YearsOfService // 依工齡
}
public class EmployeeComparer : IComparer<Employee>
{
private ComparisonType whichComparison;
public ComparisonType WhichComparison
{
get { return whichComparison; }
set { whichComparison = value; }
}
public int Compare(Employee lhs, Employee rhs)
{
// 委派給 Employee 的多參數 CompareTo 方法
return lhs.CompareTo(rhs, WhichComparison);
}
// 介面必要成員簡化實作...
}
public int CompareTo(Employee rhs, EmployeeComparer.ComparisonType which)
{
switch (which)
{
case EmployeeComparer.ComparisonType.EmpID:
return this.empID.CompareTo(rhs.empID);
case EmployeeComparer.ComparisonType.YearsOfService:
return this.yearsOfSvc.CompareTo(rhs.yearsOfSvc);
}
return 0;
}
EmployeeComparer c = Employee.GetComparer();c.WhichComparison = EmployeeComparer.ComparisonType.EmpID;empArray.Sort(c);c.WhichComparison = EmployeeComparer.ComparisonType.YearsOfService; empArray.Sort(c);| 特性 | 說明 |
|---|---|
| 關注點分離 | 排序邏輯從資料類別中抽離,符合單一職責原則 |
| 執行時期切換 | 同一比較器實例可動態改變排序策略,無需建立新物件 |
| 型別安全 | 泛型 IComparer<Employee> 避免型別轉換與 boxing/unboxing |
| 擴充性 | 新增排序欄位只需擴充列舉與 switch case,不修改現有程式碼 |
若開發自訂集合類別並需支援排序,建議在泛型定義加入約束:
public class CustomList<T> where T : IComparable<T>
{
public void Sort() { /* 內部呼叫 T.CompareTo */ }
public void Sort(IComparer<T> comparer) { /* 使用外部比較器 */ }
}
這確保放入集合的型別皆實作比較介面,編譯期即可檢查型別安全。
透過 IComparer<T> 實作策略模式,配合列舉型別控制排序邏輯,能優雅解決「單一資料類別、多種排序需求」的問題。此設計模式在處理複雜商業實體排序時極為實用,也是 .NET Framework 集合排序機制的核心設計哲學。