泛型
泛型不是語法糖,而是由框架提供的一種便捷語法,首次出現在.NET 2.0中。
1. 泛型定義
- 泛型:是一種程序特性,定義時不對類型做出明確的規定,使用時規定且不能改變。
- 一般應用:泛型集合、泛型方法、泛型類、泛型委托。
- 泛型方法:方法的返回值類型、參數類型定義成泛型類型。
- 泛型集合:如
List<T>
、Dictionary<K, V>
,所在命名空間:System.Collections.Generic
。 - 非泛型集合:
ArrayList
、Hashtable
,所在命名空間:System.Collections
。非泛型集合中可以添加任意類型,但對于數據本身來說,這是非常不安全的,并且存在裝箱和拆箱問題。- 裝箱:將值類型的元素放到集合中會被轉換成
object
類型。 - 拆箱:將一個集合的元素取出來,但這個元素本身是值類型,必須進行強制類型轉換。
- 弊端:如果存儲大量的數據,會影響性能。
- 裝箱:將值類型的元素放到集合中會被轉換成
2. 泛型賦值與約束
- default關鍵字:主要用于直接的賦值,引用類型賦值為
null
,值類型給值默認值,如T a = default(T)
。 - 泛型約束:
where T1 : class
//T1
必須是引用類型。where T2 : struct
//T2
必須是值類型。where T3 : new()
// 必須有一個無參構造方法。where T4 : 接口
// 接口約束。where T5 : 類名
// 基類約束。
- 約束是可以疊加的,比單個基類更靈活的約束目標。
- 由于泛型類型是不確定的,所以泛型類型在編譯階段無法直接轉換。可采用
dynamic
類,在運行動態解析對象類型。在編譯階段是不解析的,類型轉換不對,會在運行時報錯。
代碼示例
1. 代碼重用
public class GenericList<T>
{private T[] items;private int count;public GenericList(int capacity){items = new T[capacity];}public void Add(T item){if (count == items.Length){throw new IndexOutOfRangeException("List is full");}items[count] = item;count++;}// 其他方法...
}// 使用示例
var intList = new GenericList<int>(10);
intList.Add(1);
intList.Add(2);var stringList = new GenericList<string>(5);
stringList.Add("Hello");
stringList.Add("World");
2. 類型安全
// 使用泛型集合,無需擔心類型錯誤
List<int> intList = new List<int>();
intList.Add(1);
// intList.Add("string"); // 編譯錯誤,因為集合是 int 類型的
3. 性能優化
// 使用泛型集合避免了裝箱和拆箱操作
List<int> intList = new List<int>();
intList.Add(1);
int firstInt = intList[0]; // 直接訪問,無需拆箱// 相比之下,使用非泛型集合會有裝箱和拆箱開銷
ArrayList arrayList = new ArrayList();
arrayList.Add(1); // 裝箱
int firstValue = (int)arrayList[0]; // 拆箱
4. 減少代碼冗余
// 泛型類可以替代多個具有相似功能的類
Stack<int> intStack = new Stack<int>();
intStack.Push(1);
int topInt = intStack.Pop();Stack<string> stringStack = new Stack<string>();
stringStack.Push("Hello");
string topString = stringStack.Pop();
5. 擴展性
public interface IRepository<T>
{T Get(int id);void Add(T item);// 其他方法...
}public class ProductRepository : IRepository<Product>
{// 實現 IRepository<Product> 接口的方法
}IRepository<Product> productRepo = new ProductRepository();
Product product = productRepo.Get(1);
6. 泛型約束示例
public class GenericComparer<T> where T : IComparable<T>
{public int Compare(T x, T y){return x.CompareTo(y);}
}var comparer = new GenericComparer<int>();
int result = comparer.Compare(1, 2); // 返回 -1
7. 與集合框架的集成
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
Dictionary<string, int> ages = new Dictionary<string, int>();
ages.Add("Alice", 30);
ages.Add("Bob", 25);var olderThan30 = ages.Where(entry => entry.Value > 30);
foreach (var pair in olderThan30)
{Console.WriteLine("{0} is {1} years old.", pair.Key, pair.Value);
}
8. 泛型委托示例
public delegate TResult GenericDelegate<T, TResult>(T arg);public class GenericClass
{public static int Double(int value){return value * 2;}
}GenericDelegate<int, int> del = GenericClass.Double;
int result = del(5); // 結果為 10
高級用法與技巧
泛型在反射中的應用
創建泛型類型的實例
using System;
using System.Reflection;public class GenericClass<T>
{public T Property { get; set; }public GenericClass(T property){Property = property;}
}class Program
{static void Main(){Type genericType = typeof(GenericClass<>);Type specificType = genericType.MakeGenericType(typeof(int));object instance = Activator.CreateInstance(specificType, 42);Console.WriteLine(((GenericClass<int>)instance).Property); // 輸出: 42}
}
調用泛型方法
using System;
using System.Reflection;public class GenericMethodsClass
{public void GenericMethod<T>(T param){Console.WriteLine(param);}
}class Program
{static void Main(){var genericMethodsClass = new GenericMethodsClass();MethodInfo genericMethod = typeof(GenericMethodsClass).GetMethod("GenericMethod");MethodInfo specificMethod = genericMethod.MakeGenericMethod(typeof(string));specificMethod.Invoke(genericMethodsClass, new object[] { "Hello, World!" }); // 輸出: Hello, World!}
}
協變和逆變
協變(Covariance)
using System;
using System.Collections.Generic;public class CovarianceExample
{public static void PrintValues<T>(IEnumerable<T> collection){foreach (var item in collection){Console.WriteLine(item);}}static void Main(){IEnumerable<string> strings = new List<string> { "A", "B", "C" };// 協變使得可以將IEnumerable<string>賦值給IEnumerable<object>IEnumerable<object> objects = strings;PrintValues(objects); // 輸出: A, B, C}
}
逆變(Contravariance)
using System;
using System.Collections.Generic;public class ContravarianceExample
{public static void Compare<T>(T first, T second, IComparer<T> comparer){if (comparer.Compare(first, second) > 0){Console.WriteLine($"{first} is greater than {second}.");}else{Console.WriteLine($"{first} is less than or equal to {second}.");}}static void Main(){// 逆變使得可以將IComparer<object>賦值給IComparer<string>IComparer<object> objectComparer = Comparer<object>.Default;IComparer<string> stringComparer = objectComparer;Compare("apple", "orange", stringComparer); // 輸出可能因默認比較器而異}
}
在這兩個例子中,協變允許我們將一個更具體的集合類型(如IEnumerable<string>
)賦值給一個較不具體的類型(如IEnumerable<object>
)。而逆變則允許我們將一個較不具體的比較器類型(如IComparer<object>
)賦值給一個更具體的類型(如IComparer<string>
)。這兩個特性在泛型編程中非常有用,因為它們提供了更大的靈活性和類型安全性。