首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 泛型完整指南:從基礎語法到執行機制與約束實戰

     編輯:關於C#

什麼是泛型?

泛型 讓你在定義類別/介面/方法時,將型別參數化,實現「寫一次、套用多型別」的程式碼重用,同時保有**編譯期型別安全**與**執行期效能** (避免裝箱/拆箱)。

C# 泛型 vs C++ 模板 vs Java 泛型

特性C# 泛型C++ 模板Java 泛型
實例化時機JIT 編譯期 (執行期)編譯期編譯期 (型別擦除)
型別資訊保留完整保留 (reified)完整保留擦除後僅存原始型別
程式碼膨脹參考型別共享一份程式碼,值型別各自一份每種型別產生獨立程式碼單一份位元組碼
跨語言互操作CLR 原生支援僅 C++JVM 內部
約束機制where 子句 (基類/介面/建構函式/值/參考型別)隱式 (編譯期檢查簽名)extends/super (上界/下界)

核心語法速查

泛型類別/結構


// 合法繼承鏈
class Base { }
class Derived : Base { }
class Generic where T : Base { }           // T 必須繼承 Base
class Generic2 where T : new() { }         // T 必須有無參數建構函式
class Generic3 where T : struct { }        // T 必須為值型別
class Generic4 where T : class { }         // T 必須為參考型別
class Generic5 where T : IDisposable { }   // T 必須實作介面
// 非法:class Bad : Generic { } // int 不符合 class 約束

泛型介面與變異數


// 協變: out T (唯讀)  IEnumerable
interface IReader { T Read(); }
IReader r = new CatReader(); // 合法

// 逆變: in T (唯寫)  IComparer
interface IWriter { void Write(T item); }
IWriter w = new AnimalWriter();
IWriter w2 = w; // 合法

泛型委派


delegate bool Predicate(T value);
delegate TResult Func(T arg);

// 使用
Predicate isEven = i => i % 2 == 0;
Predicate isLong = s => s.Length > 10;

泛型方法


public static int FindIndex(T[] array, T item) where T : IEquatable
{
    for (int i = 0; i < array.Length; i++)
        if (array[i].Equals(item)) return i;
    return -1;
}

// 呼叫時型別推論
int idx = FindIndex(new[] { 1, 3, 5 }, 5); // T 推論為 int

執行機制深度解析

  1. 第一輪編譯 (CSC):產生含「型別佔位符」的 IL + 中繼資料,不具體化。
  2. JIT 編譯 (執行期):第一次遇到 `List` → 產生專屬機器碼;後續同型別直接重用。
    參考型別 (`List`, `List`) **共享同一份機器碼** (因參考大小相同);
    值型別 (`List`, `List`, `List`) **各自獨立一份**。
  3. 靜態欄位隔離:`Generic.StaticField` 與 `Generic.StaticField` 完全獨立。
  4. 約束實戰範例

    基類約束:領域模型共用邏輯

    
    abstract class Entity { public Guid Id { get; protected set; } }
    class Repository where T : Entity
    {
        public T GetById(Guid id) => _db.Set().Find(id);
        public void Add(T entity) => _db.Set().Add(entity);
    }
    

    介面約束:演算法需特定能力

    
    public T Max(IEnumerable source) where T : IComparable
        => source.Aggregate((a, b) => a.CompareTo(b) > 0 ? a : b);
    

    建構函式約束:工廠模式

    
    public T Create() where T : new() => new T();
    // 錯誤: Create(); // FileStream 無無參數建構函式
    

    值/參考型別約束:效能與語意

    
    // 僅接受值型別,避免 null 與裝箱
    struct NullableWrapper where T : struct { public T? Value; }
    
    // 僅接受參考型別,利用 null 語意
    class RefHolder where T : class { public T Instance; }
    

    泛型方法多載/覆寫規則

    宣告能否構成多載/覆寫原因
    void M(T[] a) / void M(U[] a)❌消除型別參數後簽名相同
    void M(T[] a) / void M(int x)✅非泛型簽名不同
    void M(T t) where T : A / void M(T t) where T : B❌約束不參與簽名
    覆寫時保留約束✅子類別自動繼承基類約束,不可再加強

    常見陷阱與最佳實踐

    • ⚠️ 避免在非泛型類別中宣告靜態泛型欄位:每個封閉構造型別都會有一份獨靜態欄位,易造成記憶體洩漏。
    • ⚠️ 預設值陷阱:`default(T)` 在值型別為 0/false,參考型別為 null;C# 7.1+ 可用 `default` 字面常數。
    • ✅ 優先使用泛型集合:`List`、`Dictionary` 取代 `ArrayList`/`Hashtable`,消除裝箱與型別轉換。
    • ✅ 善用介面約束而非基類約束:介面更彈性,支援多重實作。
    • ✅ 公開 API 必須加上約束:讓呼叫端在編譯期就能發現型別錯誤。
    1. 上一篇文章:
    2. 下一篇文章:
    Copyright © 程式碼之家 All Rights Reserved