泛型大幅提升類別復用率與型別安全,Visual Studio IntelliSense 加速編碼。但泛型轉型存在重大限制:泛型參數不同即為完全不同型別,即使參數有繼承關係也無法轉換。
void Exec() { List<int> list = new List<int>(); Exec(list); }
void Exec(object obj) { List<object> list = obj as List<object>; } // 轉型失敗!null
原因:編譯器將 List<int> 編譯為 List`1[[Int32]],List<object> 為 List`1[[Object]],兩者無關聯。
即使參數有繼承關係也失敗:
public class MyClassBase { }
public class MyClass : MyClassBase { }
List<MyClass> list = new List<MyClass>();
object obj = list;
List<MyClassBase> baseList = obj as List<MyClassBase>; // 失敗!
List<T> : IList<T> : IList,所有 .NET 泛型集合皆實作非泛型介面:
void Exec(object obj) {
IList list = obj as IList; // 成功!
foreach (var item in list) {
if (item is MyClassBase) { }
if (item is int) { }
if (item is string) { }
}
}
適用於不知泛型參數或可能性過多的場景。
// 類別實作方式
public class MyClass {
public object Source { get; set; }
}
public class MyClass<T> : MyClass {
public new T Source { get; set; } // new 隱藏基類成員,回傳 T
}
基類持有 object,衍生類強型別存取,外部可視為基類處理。
// 介面實作方式
public interface MyInterface {
object Source { get; set; }
}
public class MyClass<T> : MyInterface {
public T Source { get; set; } // 強型別公開介面
object MyInterface.Source { // 顯式實作非泛型介面
get { return this.Source; }
set { this.Source = (T)value; }
}
}
優點:強型別 API 與非泛型介面相容並存,編譯期型別安全。
| 模式 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| 非泛型介面 | 完全不知參數型別 | 通用、零修改現有類別 | 失去編譯期型別安全,需 runtime 檢查 |
| 基類 new 覆寫 | 自有類別體系設計時 | 語法簡單、直觀 | 隱藏基類成員易混淆、多型受限 |
| 介面顯式實作 | 公開 API 設計、框架開發 | 強型別與非泛型雙重支援、編譯期安全 | 語法較複雜、需預先定義介面 |
核心原則:泛型參數不同 = 完全不同型別。設計 API 時預留非泛型擴展點,或採用介面顯式實作模式,平衡型別安全與靈活度。