C# 2.0 引入泛型,徹底解決了 object 時代的類型不安全與性能損耗。本文系統講解泛型的核心優勢、定義語法、約束機制、泛型方法/委托/接口,並對比非泛型集合的性能差距,助你寫出更優雅、高效的代碼。
| 特性 | object 方案 | 問題 |
|---|---|---|
| 類型靈活性 | 可引用任意實例、存儲任意值 | 編譯期無法檢查,運行期才拋 InvalidCastException |
| 值類型處理 | 自動裝箱/拆箱 | 堆分配 + 類型檢查 + 拷貝,**性能損耗巨大** |
| 代碼復用 | 單一方法處理所有類型 | 失去類型語義,文檔性差,重構風險高 |
// 定義:T 為類型參數,編譯時由具體類型替換
public class GenericList<T>
{
public void Add(T input) { /* ... */ }
public T Get() { /* ... */ }
}
// 使用:閉構類型
var listInt = new GenericList<int>();
var listStr = new GenericList<string>();
var listCustom = new GenericList<MyClass>();
var listNested = new GenericList<GenericList<int>>();
// 編譯器為 listInt 生成專用代碼(概念上):
// public void Add(int input) { ... }
// public int Get() { ... }
// 多類型參數
public class Pair<T, U>
{
public T First { get; set; }
public U Second { get; set; }
}
// 約束:確保 T 實現特定介面/擁有特定能力
public class GenericList<T> where T : IEmployee
{
// 編譯器驗證 T 必須實現 IEmployee
public void Promote(T employee) { employee.Promote(); }
}
// 常用約束關鍵字
where T : struct // 值類型(除 Nullable)
where T : class // 引用類型
where T : new() // 有公共無參構造函數
where T : BaseClass // 繼承自 BaseClass
where T : IInterface // 實現介面
where T : U // T 為 U 或其衍生類
// 定義:方法級類型參數
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp = lhs; lhs = rhs; rhs = temp;
}
// 使用:類型推斷自動匹配
int a = 1, b = 3;
Swap<int>(ref a, ref b); // 顯式指定
Swap(ref a, ref b); // 隱式推斷
string s1 = "Hello", s2 = "World";
Swap(ref s1, ref s2); // 推斷為 string
// 泛型介面:System.Collections.Generic 核心
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
public interface IEnumerator<T> : IDisposable, IEnumerator
{
T Current { get; }
}
// 泛型委托:Func/Action/Predicate 全家桶
public delegate TResult Func<in T, out TResult>(T arg);
public delegate void Action<in T>(T obj);
public delegate bool Predicate<in T>(T obj);
// 使用
Func<int, int, int> add = (x, y) => x + y;
Action<string> print = Console.WriteLine;
Predicate<int> isEven = x => x % 2 == 0;
協變/逆變(in/out)使泛型介面/委托在繼承鏈中更靈活,如 IEnumerable<string> 可隱式轉為 IEnumerable<object>。
// 基準測試:添加 1000 萬整數
var list = new List<int>();
var arrayList = new ArrayList();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10_000_000; i++) list.Add(i);
sw.Stop();
Console.WriteLine($"List<int>: {sw.ElapsedMilliseconds} ms"); // ~120 ms
sw.Restart();
for (int i = 0; i < 10_000_000; i++) arrayList.Add(i); // 裝箱
sw.Stop();
Console.WriteLine($"ArrayList: {sw.ElapsedMilliseconds} ms"); // ~450 ms
結果:泛型快 **3-4 倍**,內存佔用降低 **50%+**(無裝箱對象頭)。
List<T>、Dictionary<TKey, TValue>、HashSet<T>objectwhere T : new() 實現工廠模式 T instance = new T()default(T) 獲取類型默認值(值類型為 0/false,引用類型為 null)object 或非泛型基類Dictionary<string, List<Dictionary<int, Tuple<T, U>>>> 考慮定義具體類型別名泛型是 C# 類型系統的基石,以編譯期代碼膨脹換取運行期零成本抽象。掌握 where 約束、協變逆變、泛型委托,能讓你設計出既安全又高性能的 API。下次想寫 object 參數時,請先問自己:「這裡能用泛型嗎?」