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

C# 泛型約束深度解析:where 子句實現 IDisposable 自動釋放模式

     編輯:關於C語言

前言

泛型約束(where T : ...)讓泛型類別在編譯期強制型別參數滿足特定條件,從而安全呼叫介面方法、存取基底類別成員、或保證建構函數存在。本文以 DisposableList<T> 為例,完整展示 where T : IDisposable 如何實現「移除元素時自動 Dispose()」模式,並詳細解析所有約束類型。

DisposableList 完整實現

public class DisposableList<T> : IList<T> where T : IDisposable
{
    private List<T> _items = new List<T>();

    // 核心:移除時自動 Dispose
    private void Delete(T item) => item.Dispose();

    public void Add(T item) => _items.Add(item);
    public void Insert(int index, T item) => _items.Insert(index, item);

    public bool Remove(T item)
    {
        if (_items.Remove(item))
        {
            Delete(item);
            return true;
        }
        return false;
    }

    public void RemoveAt(int index)
    {
        T item = _items[index];
        _items.RemoveAt(index);
        Delete(item);
    }

    public void Clear()
    {
        foreach (var item in _items) Delete(item);
        _items.Clear();
    }

    // 其他 IList<T> 成員委派 _items 實現...
}

使用範例

var dl = new DisposableList<StreamReader>();
dl.Add(new StreamReader("a.txt"));
dl.Add(new StreamReader("b.txt"));

dl.RemoveAt(0);        // 自動呼叫第一個 StreamReader.Dispose()
dl.Remove(reader);     // 自動呼叫指定 reader.Dispose()
dl.Clear();            // 自動呼叫所有剩餘元素 Dispose()

編譯期約束保護

// 合法:StreamReader 實作 IDisposable
var ok = new DisposableList<StreamReader>();

// 編譯錯誤:string 未實作 IDisposable
// var error = new DisposableList<string>(); // CS0311

七大約束類型完整速查

約束語法名稱要求典型用途
where T : IDisposable介面約束T 實作指定介面呼叫介面方法(如 Dispose()、CompareTo())
where T : StreamReader基底類別約束T 繼承自指定類別存取基底類別 protected 成員、呼叫虛擬方法
where T : class參考型別約束T 為 class/interface/delegate/array使用 null 比較、as 轉型、鎖定 lock(t)
where T : struct實值型別約束T 為非 Nullable 實值型別避免裝箱、使用 default(T)、堆疊配置
where T : new()無參建構函數約束T 有 public 無參建構函數工廠模式 new T()、Dapper 等 ORM 實體建立
where T : unmanaged非受控型別約束T 為 primitive/pointer/enum/struct 僅含 unmanaged 欄位跨語言互操作、stackalloc、Unsafe 操作
where T : notnull非 Null 約束T 為不可為 null 的型別(參考型別啟用 nullable context 時)避免 null 檢查、API 設計意圖明確

多重約束組合

// 必須同時滿足:繼承 TextReader、實作 IDisposable、有無參建構函數
public class AdvancedList<T> where T : TextReader, IDisposable, new()
{
    public T Create() => new T(); // 合法
}

約束以逗號分隔,型別參數需同時滿足所有條件。

約束帶來的編譯期 vs 執行期差異

場景無約束有約束
呼叫 T.Dispose()編譯錯誤(T 無此方法)編譯通過,執行期安全
new T()編譯錯誤編譯通過(需 new() 約束)
傳入錯誤型別執行期拋出例外或行為未定義編譯期直接報錯

最佳實踐建議

  1. 盡早加上約束:設計泛型類別時,先思考需要對 T 做什麼操作,對應加上約束。
  2. 介面約束優於基底類別:where T : IDisposable 比 where T : StreamReader 更鬆耦合、可測試。
  3. 避免過度約束:不需要 new() 就別加,保持泛型通用性。
  4. 文件化約束意圖:XML 註解說明為何需要此約束,助維護者理解。

總結

where 子句是 C# 泛型型別系統的基石,將執行期型別檢查前移至編譯期,同時賦予泛型程式碼呼叫特定成員的能力。DisposableList 模式展示了「約束 + 介面」實現資源管理自動化的典範用法。掌握七大約束類型與組合策略,是編寫高品質泛型程式庫的必備技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved