由於這一章非常長可能需要分成幾篇:)
20.泛型
20.1泛型類別聲明
泛型類別聲明是一個需要提供類型參數以形成實際類型的類別的聲明。
類別聲明可以選擇性地定義類型參數。
class-declaration: (類別宣告)
attributesopt class-modifiersopt class identifieropt type-parameter-listopt class –baseopt type-parameter-constraints-clauseopt class-body;opt (class-body;opt (class-body;選類型參數列表可選基底類別可選類型參數約束語句可選類別; 可選)
除非提供了類型參數列表,類別聲明可以不提供類型參數化約束語句。
提供了類型參數清單的類別聲明是一個泛型類別聲明。此外,任何嵌入到泛型類聲明或泛型結構聲明中的類,自身是一個泛型類聲明,因為必須提供包含類型的類型參數以創建構造類型(constructed type);
泛型類通過使用構造型態而被引用(§20.5)。給定泛型類別宣告
class List
這是建構型別的一些例子,List>。建構型別可以使用一個或多個參數,例如List
泛型類型不可以被「重載」;也就是說,和普通型別一樣在一個作用域內,泛型型別必須被唯一地命名。
class C{}
class C
class C{}//錯誤,C定義了兩次
然而在非限定型別名字尋找(§20.9.3)中使用的類型查找規則和成員存取(§20.9.4),確實考慮到了類型參數的個數。
20.1.1型參數
類型參數可以在一個類別聲明上提供。每個類型參數是一個簡單的標識符,它指示了用來建立一個建構類型的類型參數的佔位符。類型參數是在後面將要被提供的類型的形式佔位符。相反,型別參數§20.5.1)只是在建構型別被引用時,實際型別的一個替代。
type-parameter-list:(型別參數清單:)
type-parameters:(型別參數:)
type-parameter(型別參數)
type-parameters type- parameter(型別參數,型別參數)
type-parameter:(型別參數:)
attributesopt identifier(特性可選標識符)
在類別聲明中的每個型別參數在類別的宣告空間(§3.3)定義了一個名字。由此,它不能和另一個類型參數或在類別中聲明的成員有相同的名字。類型參數不能和型別本身有同樣的名字。
在一個類別中的型別參數的作用域(§3.7),包括基底類別 、 型別參數約束語句和類別。不像類別的成員,它沒有擴展到衍生類別。在其作用域之內,類型參數可以被用作一個型別。
type(類型):
value-type(值類型)
reference-type(引用類型)
type-parameter(類型參數)
由於類型參數可以被許多不同的實際類型實參所實例化,類型實參所實例化,類型參數與其他類型相比將略微有一些不同的操作和限制。包括如下內容。
類型參數不能用於直接聲明一個基底類型或介面
對於在類型參數上的成員查找規則,如果約束存在,則依賴於應用到該類型參數的約束。更詳細地說明參考§20.7.4。
類型參數可行的轉換依賴於應用到該類型參數上的約束(如果有的話)。詳細說明參看§20.7.4。
字面null不能轉換到由型別參數所給定的型別,除非型別參數是由一個類別約束(§20.7.4)所約束。然而可以使用一個預設值表達式(§20.8.1)來代替。此外,由一個類型參數給定的類型的值可以使用“==”和“!=”(§20.8.4)與null進行比較。
如果型別參數透過一個建構子約束(constructor-constraint)(§20.7)而約束,new表達式只能用過一個型別參數而被使用。
類型參數不能用於特性內的任何地方。
類型參數不能用於成員訪問,或表示一個靜態成員或嵌套類型的類型名字(§20.9.1、§20.9.4)。
在不安全程式碼中,類型參數不能被用作託管類型(§18.2)。
作為一種類型,類型參數純粹只是一個編譯時構件。在運行時,每個類型參數被綁定到運行時類型,它是透過泛型類型聲明所提供的類型實參所指定的。為此,在運行時,使用類型參數聲明的變數類型是封閉類型(closed type)(§20.5.2)。所有語句和表達式在執行時期執行所使用的型別參數,都是由該參數作為型別實參而提供的實際型別。
20.1.2實例類型
每個類別聲明都有與之關聯的構造類型,即實例類型(instance type)。對於一個泛型類別聲明,實例類型透過建立一個來自於類型聲明的建構型別(§20.4)而形成,它使用對應於型別參數的每一個型別實參。由於實例化類型使用類型參數,在類型參數作用域內(類別聲明之內),它是唯一有效的。實例類型在類別聲明中是this的型別。對於非泛型類,實例類型只是一個聲明類型。下面展示了幾個聲明類,以及它們的實例類型。
class A<T> //实例类型:A<T> { class B{} //实例类型:A<T>.B class C<U>{} //实例类型:A<T>.C<U> } class D{} //实例类型:D
20.1.3基類規範
在類別聲明中指定的基類可以是一個構造型別(§20.5)。一個基類其本身不能是一個型別參數,但在其作用域內可以包含型別參數。
class Extend
泛型類別聲明不能使用System.Attribute作為直接或間接基底類別。
在一個類別聲明中指定的基底介面可以是建構介面類型(§20.5)。基底介面本身不能是型別參數,但在其作用域內可以包含型別參數,下面的程式碼示範如何實作和擴充建構型別。
class C<U,V>{} Interface I1<V>{} class D:C<string , int>,I1<string>{} class E<T>:C<int,T> ,I1<T>{}
泛型類型聲明的基底介面必須滿足§20.3.1中所描述的唯一性規則。
從基底類別或介面重寫或實作方法的類別的方法,必須提供特定類型的合適方法。下面的程式碼示範了方法如何被重寫和實作。這將會在§20.1.10中進一步解釋。
class C<U,V> { public virtual void M1(U x , List<V> y){…} } interface I1<V> { V M2(V x); } class D:C<string , int>,I1<string> { public override void M1(string x , List<int> y){…} public string M2(string x){…} }
20.1.4泛型類別的成員
泛型类的所有成员都可以直接地或者作为构造类型的一部分,从任何封闭类(enclosing class)中使用类型参数。当特定的封闭构造类型在运行时被使用时,类型参数的每次使用都由构造类型所提供的实际类型实参所代替。例如
class C<V> { public V f1; public C<V> f2=null; public C(V x){ this.f1 = x; this.f2 = this; } } class Application { static void Main(){ C<int> x1= new C<int >(1); Console.WriteLine(x1.f1); //打印1 C<double> x2 = new C<double>(3.1415); Console.WriteLine(x2.f1); //打印 3.1415 } }
在实例函数成员之内,this的类型就是声明的实例类型(§20.1.2)。
除了使用类型参数作为类型和成员,在泛型类声明中也遵循和非泛型类成员相同的规则。适用于特定种类成员的附加规则将在后面几节进行讨论。
20.1.5泛型类中的静态字段
在一个泛型类声明中的静态变量,在相同封闭构造类型(§20.5.2)所有实例中被共享,但在不同封闭构造类型的实例中[1],是不被共享的。这些规则不管静态变量的类型包含那种类型参数都适用。
例如
class C<V> { static int count = 0; public C() { count++; } public static int Count{ get{return count;} } } class Application { static void Main() { C<int> x1 = new C<int>(); Console.WriteLine(C<int>.Count);//打印 1 C<double> x2 = new C<double>(); Console.WriteLine(C<int>.Count);//打印 1 C<int> x3 = new C<int>(); Console.WriteLine(C<int>.Count);//打印 2 } }
[1] 这是很容易理解的,因为在运行时,不同的封闭构造类型,是属于不同的类型,比如Listbd43222e33876353aff11e13a7dc75f6 和List98c455a79ddfebb79781bff588e7b37e 这二者的实例是不能共享静态变量的。
以上就是C#2.0 Specification(泛型一)的内容,更多相关内容请关注PHP中文网(www.php.cn)!