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

C# 泛型深度解析:告別 object 裝箱拆箱,實現類型安全與高性能

     編輯:更多程式設計知識

C# 2.0 引入泛型,徹底解決了 object 時代的類型不安全與性能損耗。本文系統講解泛型的核心優勢、定義語法、約束機制、泛型方法/委托/接口,並對比非泛型集合的性能差距,助你寫出更優雅、高效的代碼。

object 時代的痛點

特性object 方案問題
類型靈活性可引用任意實例、存儲任意值編譯期無法檢查,運行期才拋 InvalidCastException
值類型處理自動裝箱/拆箱堆分配 + 類型檢查 + 拷貝,**性能損耗巨大**
代碼復用單一方法處理所有類型失去類型語義,文檔性差,重構風險高

泛型的三大核心收益

  1. 類型安全:編譯期強類型檢查,消除運行期轉型錯誤
  2. 性能提升:值類型零裝箱,直接在棧上操作,內存佔用減半以上
  3. 代碼清晰:類型參數即文檔,IDE 智能提示完整保留

泛型類定義與使用

// 定義: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>。

性能實測:List<int> vs ArrayList

// 基準測試:添加 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>
  • ✅ 方法參數/返回值盡可能泛型化,避免 object
  • ✅ 使用 where T : new() 實現工廠模式 T instance = new T()
  • ✅ 利用 default(T) 獲取類型默認值(值類型為 0/false,引用類型為 null)
  • ❌ 避免不必要的泛型:若方法內部不依賴 T 的具體操作,直接用 object 或非泛型基類
  • ❌ 避免過度嵌套:Dictionary<string, List<Dictionary<int, Tuple<T, U>>>> 考慮定義具體類型別名

總結

泛型是 C# 類型系統的基石,以編譯期代碼膨脹換取運行期零成本抽象。掌握 where 約束、協變逆變、泛型委托,能讓你設計出既安全又高性能的 API。下次想寫 object 參數時,請先問自己:「這裡能用泛型嗎?」

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