在探討 C# 泛型之前,我們先對比一下 Java 的泛型實現。Java 的泛型僅在編譯器層面透過「型別擦除」實現,JVM 並不知情,編譯後的位元碼中不存在泛型資訊,所有型別參數都被替換為 Object 或邊界型別。這導致 Java 泛型無法解決值型別的裝箱/拆箱效能問題,且無法在執行期進行精確的型別檢查(如 instanceof T、new T()、new T[] 皆會報錯)。
與 Java 不同,.NET 的泛型在 CLR 層面有完整支援。這意味著:
換句話說,泛型型別定義能完整編譯為 MSIL,並在執行期由 JIT 根據具體型別參數「具現化」出專屬程式碼。
當 C# 編譯器產生包含泛型佔位符的 IL 後,JIT 在方法首次被呼叫時會進行「佔位符替換」,將泛型參數替換為實際型別,再編譯成 x86/x64 指令。關鍵最佳化在於:所有參考型別共用同一份機器碼,因為參考型別本質都是指標,記憶體佈局一致;而值型別則各自擁有獨立程式碼,避免裝箱並保證效能。
由於執行期完成精確匹配,泛型方法在多載解析時優先級高於基底類別方法。例如:
static void WriteMessage(MyBase b) { ... }
static void WriteMessage<T>(T obj) { ... }
MyDerived d = new MyDerived();
WriteMessage(d); // 呼叫泛型版本(精確匹配 T=MyDerived)
WriteMessage((MyBase)d); // 呼叫非泛型版本(需隱式轉型)
這提醒我們:若想統一處理基底類別及其所有衍生類,直接以基底類別為參數優於建立泛型方法,否則需在泛型內部加入執行期型別判斷(如 is、as),引入額外開銷。
.NET 泛型透過 CLR 與 JIT 的深度整合,實現了真正的型別參數化、執行期具現化與程式碼共享,不僅解決了裝箱效能問題,更在型別安全與執行效率間取得極佳平衡。下一篇將深入探討委託機制與泛型委託的協同運作。