這篇文章是翻譯的微軟的技術文章.供學習c#的朋友參考,請勿用于商業目的。http://msdn.microsoft.com/vcsharp/team/language/default.aspx 由于這一章非常長可能需要分幾篇:) 20.泛型 20.1泛型類聲明 泛型類聲明是一個需要提供類型參數以形成實際類型的類的聲明。
類聲明可以有選擇地定義類型參數。
class-declaration: (類聲明)
attributesopt class-modifiersopt class identifieropt type-parameter-listopt class –baseopt type-parameter-constraints-clauseopt class-body;opt (特性可選 類修飾符可選 類標識符可選 類型參數列表可選 基類可選 類型參數約束語句可選 類體; 可選 )
除非提供了類型參數列表,類聲明可以不提供類型參數化約束語句。
提供了類型參數列表的類聲明是一個泛型類聲明。此外,任何嵌入到泛型類聲明或泛型結構聲明中的類,自身是一個泛型類聲明,因為必須提供包含類型的類型參數以創建構造類型(constructed type);
泛型類通過使用構造類型而被引用(§20.5)。給定泛型類聲明
class List<T>{}
這是構造類型的一些例子,List<T>,List<int>和List<List<string>>。構造類型可以使用一個或多個參數,例如List<T>被稱為開放構造類型(open constructed type)。不使用類型參數的構造類型,例如List<int>被稱為封閉構造類型(closed constructed type)。
泛型類型不可以被“重載”;也就是說,和普通類型一樣在一個作用域內,泛型類型必須被唯一地命名。
class C{}
class C<V>{}//錯誤,C定義了兩次
class C<U,V>{}//錯誤,C定義了兩次
然而在非限定類型名字查找(§20.9.3)中使用的類型查找規則和成員訪問(§20.9.4),確實考慮到了類型參數的個數。
20.1.1類型參數 類型參數可以在一個類聲明上提供。每個類型參數是一個簡單的標識符,它指示了用來創建一個構造類型的類型參數的占位符。類型參數是在后面將要被提供的類型的形式占位符。相反,類型參數§20.5.1)只是在構造類型被引用時,實際類型的一個替代。
type-parameter-list:(類型參數列表:)
<type-parameters> (<類型參數>)
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<V>: V{}//錯誤,類型參數被用作基類
泛型類聲明不能使用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] 這是很容易理解的,因為在運行時,不同的封閉構造類型,是屬于不同的類型,比如List<int> 和List<string> 這二者的實例是不能共享靜
|