一、前面兩篇文章分別介紹了定義泛型類型、泛型委托、泛型介面以及聲明泛型方法: 詳解C#泛型(一) 詳解C#泛型(二) 首先回顧下如何構建泛型類: 其中,尖括弧<>中的T代表的是該泛型類的類型參數,在使用時可以指定其類型,例如,指定類型參數為整數類型,創建封閉式構造類MyClass<int>: 二、這 ...
一、前面兩篇文章分別介紹了定義泛型類型、泛型委托、泛型介面以及聲明泛型方法:
首先回顧下如何構建泛型類:
public class MyClass<T> { public void MyFunc() { //… } }
其中,尖括弧<>中的T代表的是該泛型類的類型參數,在使用時可以指定其類型,例如,指定類型參數為整數類型,創建封閉式構造類MyClass<int>:
MyClass<int> myObj = new MyClass<int>();
二、這一篇我們瞭解一下泛型的作用機制,泛型是運行時起作用的一套機制,根據運行時類型參數被指定為值類型還是引用類型其使用方式有所不同:
1.當類型參數被指定為值類型時,會在第一次指定該特定值類型的類型時創建該類型唯一的專用化泛型類型,泛型類型中的類型參數會被替換為相應的值類型;
※此時,運行時會創建不同封閉式構造類型的類型信息對象,它們的類型句柄指向不同的類型信息對象,不同封閉式構造類型的方法句柄也指向不同的方法信息對象;
2.當類型參數被指定為引用類型時,會在第一次指定任意引用類型時創建一個通用化泛型類型,泛型類型中的類型參數會被替換為該引用類型,併在之後每次指定為引用類型時重用該泛型類型並修改其中類型參數的類型;造成這種差異的原因可能在於所有的引用大小相同;
※此時,運行時依然會創建不同封閉式構造類型的類型信息對象,它們的類型句柄也指向不同的類型信息對象,但是它們共用一套方法句柄,即不同封閉式構造類型的方法句柄指向同一個方法信息對象;
3.對於給定的泛型類:
public class MyClass<T>
{
public void MyFunc()
{
//…
}
}
獲取不同封閉式構造類型的類型句柄和方法句柄:
Type type1 = typeof(MyClass<int>);
Type type2 = typeof(MyClass<long>);
Type type3 = typeof(MyClass<string>);
Type type4 = typeof(MyClass<Array>);
//以下類型句柄各不相同
Console.WriteLine(type1.TypeHandle.Value);
Console.WriteLine(type2.TypeHandle.Value);
Console.WriteLine(type3.TypeHandle.Value);
Console.WriteLine(type4.TypeHandle.Value);
//最後兩個方法句柄相同,其它方法句柄各不相同
Console.WriteLine(type1.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type2.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type3.GetMethod("MyFunc").MethodHandle.Value);
Console.WriteLine(type4.GetMethod("MyFunc").MethodHandle.Value);
※在訪問任何泛型類型之前,CLR會先創建MyClass<>的類型信息對象;
列印結果:
可以發現,最後兩個泛型類型的MyFunc方法的方法句柄指向相同;但是不同類型參數的情況下,還是會創建對應的泛型類型對象,這使得泛型單例成為可能:
三、對於封閉式構造類型,只要其類型參數不完全相同,CLR就會在初次訪問該類型之前創建該類型的類型信息對象並調用其對應唯一的靜態構造函數,例如對於有靜態構造函數的泛型類MyClass<T>,在初次訪問MyClass<int>、MyClass<string>等封閉式構造類之前都會調用一次其對應唯一的靜態構造函數,這也是創建泛型單例的基礎:
public class MyClass<T>
{
static MyClass()
{
Console.WriteLine(typeof(T).FullName);
}
}
MyClass<int> obj1 = new MyClass<int>();
MyClass<long> obj2 = new MyClass<long>();
MyClass<Array> obj4 = new MyClass<Array>();
列印結果:
四、運行時動態構建泛型:
Type myType = typeof(MyClass<>); //獲取未指定任何類型參數的開放式構造類的類型信息,多個類型參數時添加,:typeof(MyClass<,>) myType = myType.MakeGenericType(typeof(int)); //通過類型信息的實例方法MakeGenericType()構建指定所有類型參數的封閉式構造類的類型信息,如未指定所有類型參數會拋出異常ArgumentException //也可以直接獲取封閉式構造類的類型信息,當類型參數在一開始就確定時推薦使用此種方式 //myType = typeof(MyClass<int>); //多個類型參數時需要同時指定:typeof(MyClass<int, string>)
註意:通過反射只可以獲取未指定任何類型參數的開放式構造類MyClass<,>的類型信息和指定所有類型參數的封閉式構造類MyClass<int, string>的類型信息,即無法獲取MyClass<int, >的類型信息;
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的認可是我寫作的最大動力!
作者:Minotauros
出處:https://www.cnblogs.com/minotauros/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。