通過創建一個類型參數被綁定到的運行時類型的實例,並調用該類型的默認構造函數,就可以執行對象創建表達式。運行時類型可以是引用或者值類型。 20.8.3運算符的類型 typeof運算符可以用於類型參數。其結果是被綁定到類型參數的運行時類型的System.Type對象。typeof運算符也可以被用於構造類型。 class X <T> { public static void PrintTypes() { Console.WriteLine(typeof(T).FullName); Console.WriteLine(typeof(X<X<T>>).FullName); } } class M { static void Main() { X<int>.PrintTypes(); } } 先前的程序將打印如下。 System.Int32 X<X<Sytem.Int32>> Typeof運算符不能用於沒有指定類型實參的泛型類型聲明的名字。 class X<T>{…} class M { static void Main() { Type t = typeof(X); //錯誤,X需要類型實參 } } 20.8.4引用相等運算符 如果T由一個類約束而約束,引用類型相等運算符可以被用於比較類型參數T的值。 引用類型相等運算符的用法可以讓類型參數T的實參很容易地與其他為null的實參進行比較,即使T沒有類約束也如此。在運行時,如果T是一個值類型,比較的結果將是false。
下面的例子檢查一個非約束類型參數類型的實參是否是null。 class C<T> { void F(T x) { if(x==null) thow new ArgumentNullException(); … } }
即使是T可以表示一個值類型,x==null構件也是允許的,並且當T是值類型時,其結果被簡單的定義為false。 20.8.5 is運算符 在開放類型上的is運算符操作遵循通常的規則(§7.9.9)。如果e或T的編譯時類型是一個開放類型,那麼在運行時對於e和T將總是執行動態類型檢查。 20.8.6as運算符 只要T有一個類約束,類型參數T可被用在as運算符的右邊。這種限制是需要的,因為值null可能被作為運算符的結果返回。 class X { public T F<T>(object o) where T:Attribute { return o as T; //ok,T有一個類約束 } public T G<T>(object o) { return o as T; //錯誤,T沒有約束 } } 在as運算符(§7.9.10)的當前規范中,對於表達式e as T最後一點表明,如果從e的編譯時類型到T,不存在有效的顯式引用轉換,將會出現編譯時錯誤。對於泛型,這條規則稍微作了修改。如果E的編譯時類型或T是一個開放類型,在這種情況下將不會出現編譯時錯誤;相反,運行時檢查將會執行。
20.9.3簡單名字 如下內容可替換§7.5.2。 簡單名字由一個標識符,其後可跟隨可選的類型參數列表。 simple-name:(簡單名字:) identifIEr type-argument-list opt(標識符 類型實參列表可選) 對於I或I<A1,…,AN>形式的簡單名字,這裡I 是一個標識符,I<A1,…,AN>是一個可選類型實參列表,可以被按如下方式計算和分類。 如果簡單名字出現在塊內,並且如果塊的局部變量聲明空間包含由I給定名字的局部變量或參數,那麼,這個簡單名字引用該局部變量和參數,並且作為一個變量而被分類。如果類型實參列表被指定,將會出現編譯時錯誤。 如果簡單名字出現在泛型方法聲明體之內,並且如果該聲明包含由I給定名字的類型參數,那麼簡單名字引用那個類型參數,如果只定了類型實參列表被,將會出現編譯時錯誤。 否則,對於以直接封閉類、結構或枚舉聲明的實例類型開始的類型T的每個實例,繼續采用每個封閉外部類或結構聲明的實例類型(如果有的話)。 - 如果T的聲明包括由 I給定名字的類型參數,那麼,簡單名字引用該類型參數。如果類型實參列表被指定,將會出現編譯時錯誤。 - 否則,如果在T 中I的成員查找產生一個匹配 u 如果T是直接封閉類或結構類型的實例類型, 並且查找標識一個或多個方法,結果將是一個帶有與this表達式關聯的方法組。如果類型實參列表被指定,它被用在一個泛型方法調用中(§20.6.3)。 u 如果T是直接封閉類或結構類型的實例類型,如果查找標識一個實例成員,並且引用出現在一個實例構造函數、實例方法或一個實例訪問器的塊之內,其結果將和this.I形式的成員訪問相似。如果類型實參被指定,將出現編譯時錯誤。 u 否則,結果與T.I或T.I<A1,…,AN>形式的成員訪問相似。在這種情況下,引用實例成員的簡單名字將是一個編譯時錯誤。
否則,對於帶有每個簡單名字出現在其中的命名空間的命名空間N,繼續采用每個封閉命名空間(如果有的話),並以全局命名空間結束,下面的步驟將被計算,直到一個實體被定位。 - 如果I是在N 中的一個命名空間的名字,並且沒有指定類型實參列表,那麼簡單名字將引用該命名空間。 - 否則,如果I是在帶有匹配類型參數數量的N中的一個可訪問類型的名字,那麼簡單類型引用由給定類型實參構造的那個類型。 u 如果命名空間聲明包含一個關聯由I給定名字的using 別名指令,這裡I是一個導入命名空間或類型,並且沒有指定類型實參列表,那麼簡單名字引用該命名空間或類型。 u 否則,如果由命名空間聲明的using 命名空間指令導入的命名空間,恰好包含一個由I給定名字的,匹配類型參數數量的類型,那麼簡單名字引用由給定類型實參構造的類型。 u 否則,如果由命名空間聲明的using命名空間指令導入的命名空間,包含多個由I給定名字,匹配類型參數數量的類型,那麼簡單名字是不明確的,將導致編譯時錯誤 l 否則,由簡單名字給定的名字是未定義的,將導致編譯時錯誤。
如果E是一個屬性訪問、索引器訪問、變量或值,其類型是T,並且在T中I的成員查找產生一個匹配,那麼E.I按如下方式被計算和分類。 - 首先,如果E是一個屬性或索引器訪問,那麼屬性或索引器訪問的值將被獲得(§7.1.1),並且E被重分類為值。 - 如果I標識一個或多個方法,那麼結果是一個帶有關聯的E的實例表達式的方法組。如果類型實參列表被指定,它將在泛型方法調用中被使用(§20.6.3)。 - 如果I標識一個實例屬性、實例字段或實例事件,並且如果類型實參列表被指定,將產生編譯時錯誤。 - 如果I標識一個實例屬性,那麼結果是一個帶有關聯的E 的實例表達式。 - 如果T是一個類類型並且I 標識一個類類型的實例字段 u 如果E的值是null,那麼將會拋出System.NullReferenceException。 u 否則,如果該字段是只讀的,並且引用出現在字段聲明的類的實例構造函數之外,那麼結果是值,也就是由E引用的對象中 I的值。 u 否則,結果是變量,也就是由E引用的對象中字段I。 - 如果T是一個結構類型,並且I 標識該結構類型的實例字段 u 如果E是一個值,或者如果字段是只讀的,並且引用出現在字段聲明的結構的實例構造函數之外,那麼結果是一個值,也就是由E給定的結構實例中字段I的值。 u 否則,結果是一個變量,也就是由E給定結構實例中的字段I; - 如果I標識一個實例事件 u 如果引用出現在該事件被聲明的類或結構之內,並且事件被聲明時沒有使用事件訪問器聲明,那麼E.I就好像I是一個實例字段一樣被處理。 u 否則,結果是一個帶有關聯的E的實例表達式。 否則,E.I是一個無效成員引用,將導致編譯時錯誤。
20.9.5方法調用 如下內容可替換§7.5.5.1中描述方法調用的編譯時處理部分。 對於M(A)形式的方法調用的編譯時處理,其中M是一個方法組(可能包含一個類型實參列表),A是可選實參列表,由如下步驟組成。 方法調用的候選集合被構造。對於每個與方法組M關聯的方法F - 如果F是非泛型的,當如下成立時F是候選項 u M沒有類型實參列表,並且 u 對於A(§7.4.2.1) ,F是適用的。 - 如果F是泛型,並且M沒有類型實參列表,當如下成立時,F是候選項 u 類型推斷成功(§20.6.4),對於調用推斷出類型實參的列表,並且 u 一旦推斷的類型實參替換了對應方法類型參數,F的參數列表對於A是適用的,並且 u 在替換類型實參後,F 的參數列表,與適用的可能以其擴展形式(§7.4.2.1)在相同的類型中作為F而聲明的非泛型方法是不同的。 - 如果F是泛型,並且M包括一個類型實參列表,當如下成立時,F是候選項 u F和在類型實參列表中提供的一樣,具有相同數量的方法類型參數,並且 u 一旦,類型實參替換對應的方法類型參數,F的參數列表對於A 是可適用的(§7.4.2.1)。 候選方法的集合被縮減到只包含從深度派生類型而來的方法:對於在集合中的每個C.F方法,C是F在其中聲明的類型,在C的基類型中聲明的所有方法都被從集合中刪除。 如果候選方法的結果集合是空的,那麼沒有可適用的方法存在,並且會出現編譯時錯誤。如果候選方法並不是在同一類型中聲明的,方法調用將是不明確的,並且會出現編譯時錯誤(這後一種情況,只可能出現在對於一個在具有多重直接基接口的接口中的方法的調用,如§13.2.5的描述)。
候選方法集合的最佳方法使用重載決策規則(§7.4.2)標識。如果一個單一的最佳方法不能被標識,該方法調用是不明確的,並產生編譯時錯誤。當執行重載決策時,泛型方法的參數在將對應的方法類型參數替換為類型實參(提供的或推斷的)之後將被考慮。 被選擇的最佳方法的最後驗證被執行 - 方法在方法組的上下文中是有效的:如果方法是一個靜態方法,方法組必須通過類型源自於簡單名字或成員訪問。如果該最佳方法是一個實例方法,方法組必須通過一個變量或值或者基類訪問(base-Access)源自於簡單名字或成員訪問。如果這些需求都不滿足,那麼將會出現編譯時錯誤。 - 如果該最佳方法是一個泛型方法,類型實參(提供的或推斷的)將被針對聲明在泛型方法之上的約束作出檢查。如果任何類型實參不滿足對應類型參數的約束,將產生一個編譯時錯誤。 一旦方法根據前面的步驟被選擇和驗證,實際的運行時調用將根據§7.4.中的函數成員調用規則而被處理。 20.9.6委托創建表達式 如下內容可替換§7.5.10.3中委托創建表達式的編譯時處理部分。 對於new D(E)形式的委托創建表達式的編譯時處理,其中D 是一個委托類型,E是一個表達式,由如下步驟組成。 如果E是一個方法組 - 對應於E(A)形式的方法調用,一個單一的方法調用將被選擇。 u D的參數類型和修飾符(ref或out)被用作實參類型和實參列表A的修飾符。 u 在適用的測試和類型推斷中,轉換不予考慮。在隱式轉換足夠的實例中,類型要求是同一的。 u 重載決策步驟不會執行。相反,候選的集合必須恰好包含一個與D兼容的方法(接著使用類型實參替換類型參數),並且這個方法將變成新創建委托所引用的方法。如果沒有匹配的方法存在,或有多個匹配的方法存在,將發生編譯時錯誤。