.NET 1.x 時代,集合類別 (如 Stack) 僅能用 object 儲存任意型別,導致兩大問題:
int, struct) 存入 object 需在堆積配置包裝物件,取出需拆箱,大量操作效能極差。stack.Push(1); stack.Push("str"); 編譯通過,執行期 Pop() 轉型失敗拋出 InvalidCastException。
public class Stack
{
private T[] _items;
private int _top = -1;
public Stack(int capacity) => _items = new T[capacity];
public void Push(T item) => _items[++_top] = item;
public T Pop() => _items[_top--];
public T Peek() => _items[_top];
}
T 為型別參數 (佔位符),實例化時指定具體型別:var intStack = new Stack<int>(100);。intStack.Push("str") 編譯錯誤。Stack<int>, Stack<string>) 產生專屬機器碼,實值型別直接內嵌儲存。where)| 約束 | 語法 | 含義 |
|---|---|---|
| 基底類別 | where T : BaseClass | T 必須繼承自 BaseClass (單一) |
| 介面 | where T : IInterface | T 必須實作介面 (可多個) |
| 無參建構函式 | where T : new() | T 必須有 public 無參建構函式 |
| 參考型別 | where T : class | T 必須為 class/interface/delegate/array |
| 實值型別 | where T : struct | T 必須為非 Nullable 實值型別 |
| 非受控型別 | where T : unmanaged | C# 7.3+,T 為非受控型別 (可用於 stackalloc) |
| 預設建構函式 | where T : notnull | C# 8.0+,T 不可為 nullable |
// 多重約束:T 繼承 Base 且實作 IComparable,且有無參建構函式
public class Node where T : BaseClass, IComparable, new() { ... }
// 多型別參數各自約束
public class Pair where T : class where U : struct { ... }
約束效益:在泛型類別內可呼叫約束保證的成員 (如 T.CompareTo、new T())。
方法層級引入型別參數,獨立於類別泛型參數。
public static void Swap(ref T a, ref T b) { T t=a; a=b; b=t; }
public void PushRange(Stack stack, params T[] items) { foreach(var i in items) stack.Push(i); }
// 呼叫:型別推論自動推導 T
Swap(ref x, ref y);
PushRange(intStack, 1,2,3,4,5);
核心原則:每個封閉構造型別擁有獨立的靜態欄位/建構函式。
class Counter { public static int Count = 0; }
Counter.Count++; // 1
Counter.Count++; // 2
Counter.Count++; // 1 (獨立計數)
static Counter()) 在該封閉型別首次被存取 (建立實例或存取靜態成員) 時由 CLR 自動執行一次。Counter<T>) 無靜態狀態,只有具體化後 (Counter<int>) 才有。Node<T,U>) 檢查簽名衝突,允許潛在衝突 (如 add(T,U)、add(U,T)、add(int,int) 共存)。
class Node
{
public T Add(T a, U b) => a;
public T Add(U a, T b) => b;
public int Add(int a, int b) => a + b; // 非泛型多載優先
}
var n1 = new Node(); n1.Add(2,3); // 呼叫 int Add(int,int) (非泛型優先)
var n2 = new Node(); n2.Add("s", 1); // 呼叫 Add(T,U)
若移除非泛型多載,Node 會因 Add(T,U) 與 Add(U,T) 簽名相同而編譯錯誤 (模糊)。
同多載:衍生類別覆寫基底泛型虛擬方法時,簽名必須完全一致 (含型別參數)。
delegate TResult Func(T arg); (框架內建 Func/Action 族)。in/out):IEnumerable, IComparer。泛型是 C# 2.0 最具影響力的特性,實現 型別安全、高效能、程式碼重用 三贏。掌握 where 約束、靜態成員隔離、多載解析規則,能設計出優雅且高效的泛型庫。