C# 中的 泛型(Generics) 是一種強大的編程特性,允許開發者在不預先指定具體數據類型的情況下編寫代碼。通過泛型,C# 能夠讓我們編寫更靈活、可重用、類型安全且性能優良的代碼。泛型廣泛應用于類、方法、接口、委托、集合等多個方面。
本文將詳細介紹 C# 中泛型的基本概念、常見用法、類型約束以及一些高級應用,幫助你更深入地理解泛型的強大功能及其最佳實踐。
一、泛型的基本概念
1.1 什么是泛型?
泛型使得你能夠編寫能夠操作多種數據類型的代碼,而不需要在代碼中硬編碼具體的數據類型。通過類型參數(例如 T
),你可以在運行時決定具體的類型,從而提高代碼的重用性和靈活性。
在 C# 中,泛型可以應用于:
- 泛型類
- 泛型方法
- 泛型接口
- 泛型委托
- 泛型集合
1.2 泛型類
泛型類 是在定義類時使用類型參數,并且在類的實例化時指定具體的類型。這使得同一個類可以用來處理不同類型的數據。
示例:
public class Box<T>
{private T _value;public void SetValue(T value){_value = value;}public T GetValue(){return _value;}
}public class Program
{public static void Main(){Box<int> intBox = new Box<int>();intBox.SetValue(123);Console.WriteLine(intBox.GetValue()); // 輸出 123Box<string> stringBox = new Box<string>();stringBox.SetValue("Hello");Console.WriteLine(stringBox.GetValue()); // 輸出 Hello}
}
在這個例子中,Box<T>
是一個泛型類,T
是類型參數。通過不同的類型參數,Box
類可以同時處理不同的數據類型。
1.3 泛型方法
泛型方法 允許你在方法定義時使用類型參數。方法可以在調用時決定具體的類型。
示例:
public class Program
{public static void Print<T>(T value){Console.WriteLine(value);}public static void Main(){Print(123); // 輸出 123Print("Hello"); // 輸出 HelloPrint(3.14); // 輸出 3.14}
}
Print<T>
方法能夠處理不同類型的數據,并且在調用時根據傳入的參數類型來自動推斷 T
的類型。
1.4 泛型接口
泛型接口 允許接口聲明時不指定具體的類型,而是在實現該接口的類中指定具體類型。通過這種方式,接口可以與多種數據類型兼容。
示例:
public interface IStorage<T>
{void Add(T item);T Get(int index);
}public class StringStorage : IStorage<string>
{private List<string> items = new List<string>();public void Add(string item){items.Add(item);}public string Get(int index){return items[index];}
}public class Program
{public static void Main(){IStorage<string> storage = new StringStorage();storage.Add("Item 1");storage.Add("Item 2");Console.WriteLine(storage.Get(0)); // 輸出 Item 1}
}
在這個例子中,IStorage<T>
是一個泛型接口,StringStorage
類實現了該接口,并且指定 T
為 string
類型。
二、泛型類型參數的約束
C# 允許你為泛型類型參數添加約束,以確保泛型在特定類型范圍內使用,從而提升類型安全性。
2.1 常見的泛型約束
class
:限制類型參數為引用類型。struct
:限制類型參數為值類型。new()
:限制類型參數必須有無參數構造函數。where T : BaseClass
:限制類型參數為某個特定的類或接口。
2.2 約束示例
示例1:限制類型為值類型
public class ValueTypeContainer<T> where T : struct
{private T _value;public ValueTypeContainer(T value){_value = value;}public void Display(){Console.WriteLine(_value);}
}public class Program
{public static void Main(){ValueTypeContainer<int> intContainer = new ValueTypeContainer<int>(123);intContainer.Display(); // 輸出 123// 編譯錯誤:不能傳遞引用類型// ValueTypeContainer<string> stringContainer = new ValueTypeContainer<string>("Hello");}
}
示例2:使用接口約束
public interface IComparable
{int CompareTo(object obj);
}public class Repository<T> where T : IComparable
{public void Print(T item){Console.WriteLine(item.ToString());}
}public class Program
{public static void Main(){Repository<string> repo = new Repository<string>();repo.Print("Hello"); // 輸出 Hello}
}
2.3 多個約束的使用
你可以為一個泛型類型參數指定多個約束,確保泛型類型滿足多個條件。
示例:
public class Repository<T> where T : class, IComparable, new()
{public void Print(T item){Console.WriteLine(item.ToString());}
}
三、泛型的高級用法
3.1 多個類型參數
泛型不僅支持一個類型參數,還可以支持多個類型參數,這使得你可以創建更加靈活的泛型類型。
示例:
public class Pair<T1, T2>
{private T1 first;private T2 second;public Pair(T1 first, T2 second){this.first = first;this.second = second;}public void Print(){Console.WriteLine($"First: {first}, Second: {second}");}
}public class Program
{public static void Main(){Pair<int, string> pair = new Pair<int, string>(1, "One");pair.Print(); // 輸出 First: 1, Second: One}
}
3.2 泛型與集合類
C# 的泛型集合類(如 List<T>
、Dictionary<TKey, TValue>
、Queue<T>
等)允許我們高效地操作數據,并且避免了類型轉換的潛在問題。
示例:
List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);
Console.WriteLine(numbers[0]); // 輸出 1
3.3 泛型委托
泛型委托使得委托能夠處理多種類型的方法。你可以定義一個泛型委托,使其接受不同類型的參數,并且在運行時動態選擇具體的方法。
示例:
public delegate void PrintDelegate<T>(T value);public class Program
{public static void Main(){PrintDelegate<int> printInt = (value) => Console.WriteLine(value);printInt(10); // 輸出 10PrintDelegate<string> printString = (value) => Console.WriteLine(value);printString("Hello"); // 輸出 Hello}
}
3.4 泛型與 LINQ
C# 的 LINQ 查詢使用泛型來確保查詢結果的類型安全。你可以利用 LINQ 對集合進行高效的查詢、排序和過濾操作。
示例:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();foreach (var num in evenNumbers)
{Console.WriteLine(num); // 輸出 2, 4
}
四、泛型的優勢
- 類型安全:泛型提供編譯時的類型檢查,避免了運行時類型錯誤。
- 性能優化:泛型避免了類型轉換的開銷,因此在處理大量數據時具有較好的性能。
- 代碼重用:通過泛型,我們可以編寫能夠處理多種類型數據的代碼,而無需重復編寫多個版本。
- 靈活性:泛型使得我們能夠編寫通用的代碼,且不需要犧牲類型安全。
五、總結
泛型是 C# 中的一項強大特性,能夠讓你編寫類型安全、靈活、可重用且高效的代碼。通過泛型,開發者可以避免在類型轉換時出現的錯誤,并且能夠編寫高度通用的類、方法、接口等。掌握泛型的使用,能夠幫助開發者在處理復雜數據結構和編寫高效代碼時更得心應手。
無論是常見的泛型類、方法、接口,還是泛型在 LINQ 和集合類中的應用,了解泛型的各種用法和最佳實踐,能夠使你寫出更簡潔、更可維護的代碼。