泛型是 C# 2.0 引入的核心特性,提供型別安全、效能與重用性的三重保障。本文系統涵蓋泛型類別、方法、介面、委派、約束、協變/逆變、進階模式與最佳實踐。
// 泛型類別
public class Stack
{
private T[] _items;
private int _count;
public Stack(int capacity = 10)
{
_items = new T[capacity];
}
public void Push(T item)
{
if (_count == _items.Length) Resize();
_items[_count++] = item;
}
public T Pop()
{
if (_count == 0) throw new InvalidOperationException("Stack empty");
return _items[--_count];
}
public T Peek() => _count > 0 ? _items[_count - 1] : default;
public int Count => _count;
private void Resize()
{
Array.Resize(ref _items, _items.Length * 2);
}
}
// 使用
var intStack = new Stack();
intStack.Push(1);
intStack.Push(2);
int value = intStack.Pop(); // 型別安全,無裝箱
public static class Utility
{
// 交換兩個變數
public static void Swap(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
// 取得陣列最大值
public static T Max(T[] array) where T : IComparable
{
if (array.Length == 0) throw new ArgumentException("Empty array");
T max = array[0];
for (int i = 1; i < array.Length; i++)
if (array[i].CompareTo(max) > 0) max = array[i];
return max;
}
// 建立預設值字典
public static Dictionary CreateDictionary()
where TKey : notnull
{
return new Dictionary();
}
}
| 約束 | 語法 | 說明 | 範例 |
|---|---|---|---|
| 實值型別 | where T : struct | 不可為 null | int, double, DateTime, 自訂 struct |
| 參考型別 | where T : class | 可為 null | string, 自訂 class, 介面, 委派 |
| 建構函式 | where T : new() | 需有無參數建構函式 | new T() |
| 基底類別 | where T : BaseClass | 繼承關係 | Entity, Control |
| 介面 | where T : IInterface | 實作介面 | IComparable<T>, IDisposable |
| 非受控型別 | where T : unmanaged | 無參考欄位 | int, bool, 自訂 struct (無 ref 欄位) |
| 可為 null 實值型別 | where T : struct? | C# 9+ | int?, DateTime? |
| 預設建構函式 + 實值型別 | where T : struct, new() | 組合約束 | 所有 struct 隱含有 new() |
// 字典鍵值對
public class Pair
{
public TKey Key { get; set; }
public TValue Value { get; set; }
public Pair(TKey key, TValue value)
{
Key = key;
Value = value;
}
public void Deconstruct(out TKey key, out TValue value)
{
key = Key;
value = Value;
}
}
// 使用
var pair = new Pair("Age", 25);
var (key, value) = pair; // 解構
// 協變:out T (只作為輸出/回傳)
public interface IEnumerable : IEnumerable
{
IEnumerator GetEnumerator();
}
// 逆變:in T (只作為輸入/參數)
public interface IComparer
{
int Compare(T x, T y);
}
// 使用協變
IEnumerable strings = new List();
IEnumerable
public abstract class Entity where T : Entity
{
public int Id { get; protected set; }
public bool Equals(T other) => other != null && Id == other.Id;
public override bool Equals(object obj) => obj is T other && Equals(other);
public override int GetHashCode() => Id.GetHashCode();
public static bool operator ==(Entity a, Entity b)
{
if (ReferenceEquals(a, b)) return true;
if (a is null || b is null) return false;
return a.Equals(b);
}
public static bool operator !=(Entity a, Entity b) => !(a == b);
}
public class User : Entity
{
public string Name { get; set; }
}
public class Product : Entity
{
public string SKU { get; set; }
}
public class PersonBuilder where T : PersonBuilder
{
protected string _name;
protected int _age;
public T WithName(string name)
{
_name = name;
return (T)this;
}
public T WithAge(int age)
{
_age = age;
return (T)this;
}
public Person Build() => new Person(_name, _age);
}
public class EmployeeBuilder : PersonBuilder
{
public EmployeeBuilder WithCompany(string company)
{
// 擴充屬性
return this;
}
}
public interface ISerializer
{
string Serialize(T obj);
T Deserialize(string data);
}
public class JsonSerializer : ISerializer
{
public string Serialize(T obj) => System.Text.Json.JsonSerializer.Serialize(obj);
public T Deserialize(string data) => System.Text.Json.JsonSerializer.Deserialize(data);
}
public class XmlSerializer : ISerializer
{
public string Serialize(T obj)
{
var xs = new System.Xml.Serialization.XmlSerializer(typeof(T));
using var sw = new StringWriter();
xs.Serialize(sw, obj);
return sw.ToString();
}
public T Deserialize(string data)
{
var xs = new System.Xml.Serialization.XmlSerializer(typeof(T));
using var sr = new StringReader(data);
return (T)xs.Deserialize(sr);
}
}
// 使用
ISerializer serializer = new JsonSerializer();
string json = serializer.Serialize(new Person("John", 30));
public interface IRepository where T : class
{
T GetById(int id);
IEnumerable GetAll();
void Add(T entity);
void Update(T entity);
void Delete(T entity);
}
public class Repository : IRepository where T : class
{
private readonly DbContext _context;
public Repository(DbContext context) => _context = context;
public T GetById(int id) => _context.Set().Find(id);
public IEnumerable GetAll() => _context.Set().ToList();
public void Add(T entity) => _context.Set().Add(entity);
public void Update(T entity) => _context.Set().Update(entity);
public void Delete(T entity) => _context.Set().Remove(entity);
}
// 註冊 (DI 容器)
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
// 使用
public class UserService
{
private readonly IRepository _userRepo;
private readonly IRepository _orderRepo;
public UserService(IRepository userRepo, IRepository orderRepo)
{
_userRepo = userRepo;
_orderRepo = orderRepo;
}
}
| 面向 | 影響 | 建議 |
|---|---|---|
| 程式碼膨脹 | 每個具體型別產生獨立程式碼 | 避免過度泛型化,熱點路徑可接受 |
| 實值型別 | 每個 struct 產生專屬程式碼 | 優點:無裝箱;缺點:程式碼重複 |
| 參考型別 | 共享同一組程式碼 (型別抹除) | 記憶體效率佳 |
| JIT 編譯 | 首次使用時編譯 | 預熱關鍵路徑 |
// 1. 靜態欄位每個封閉型別獨立
public class Counter
{
public static int Count = 0; // Counter.Count ≠ Counter.Count
}
// 2. 遞迴泛型定義
public class Node
{
public T Value;
public Node Next; // 正確
// public Node> Next; // 錯誤:無限遞迴
}
// 3. 預設值陷阱
public T GetDefault() => default; // struct 回傳 0/false,class 回傳 null
// 4. 運算子限制
public T Add(T a, T b) // 錯誤:T 不支援 +
{
return a + b; // 需約束:where T : IAdditionOperators (C# 11+)
}
// C# 11: 靜態虛擬介面成員 (數學運算)
public T Sum(IEnumerable values) where T : INumber
{
T sum = T.Zero;
foreach (var v in values) sum += v;
return sum;
}
// C# 11: required 修飾詞
public class Person
{
public required string Name { get; init; }
public required int Age { get; init; }
}
// C# 12: 預設 lambda 參數
var factory = () => new List(); // 隱含型別
// .NET 7: System.Numerics 泛型數學
public T Calculate(T a, T b) where T : INumber
{
return T.Max(a, b) * T.One;
}
泛型提供 型別安全 (編譯期檢查)、效能 (實值型別無裝箱)、重用性 (一份程式碼服務多型別) 三大核心價值。掌握約束條件、協變/逆變、CRTP、策略模式泛型化等進階模式,能設計出優雅且高效的 API。現代 C# 持續強化泛型能力 (靜態虛擬介面、泛型數學、required 修飾詞),使泛型成為類別庫與框架設計的基石。