Share via


反映和泛用型別

從反映 (Reflection) 的觀點來看,泛型型別和一般型別之間的差異在於泛型型別會將一組型別參數 (如果它是泛型型別定義) 或是型別引數 (如果它是建構的型別) 與它產生關聯。 泛型方法與一般方法的差異處也是同樣的情形。

了解反映如何處理泛型型別和方法時,要注意兩個要點。

  • 泛型型別定義和泛型方法定義的型別參數是由 Type 類別的執行個體所表示。

    注意事項注意事項

    Type 物件表示泛型型別參數時,Type 的許多屬性和方法都有不同的行為;這些差異會記錄在這些屬性和方法的主題中。例如,請參閱 IsAutoClassDeclaringType。此外,某些成員只有在 Type 物件表示泛型型別參數時,才會是有效的。如需範例,請參閱 GetGenericTypeDefinition

  • 如果 Type 的執行個體表示泛型型別,則它會包含表示型別參數 (若是泛型型別定義) 或型別引數 (若是建構的型別) 的型別之陣列。 表示泛型方法的 MethodInfo 類別之執行個體,也是同樣的情況。

反映提供了 TypeMethodInfo 的方法,可讓您存取型別參數的陣列,以及判斷 Type 的執行個體是否表示型別參數或實際型別。

如需示範這裡所討論之方法的範例程式碼,請參閱 HOW TO:使用反映檢視和執行個體化泛型型別

下列討論內容假設您熟悉泛型的用語,例如,型別參數和引數以及開放式或封閉式建構的型別之間的差異。 如需詳細資訊,請參閱 .NET Framework 中的泛型

本概觀包含下列各節:

  • 這是泛型型別還是方法?

  • 產生封閉式泛型型別

  • 檢查型別引數和型別參數

  • 不變項目

  • 相關主題

這是泛型型別還是方法?

當您使用反映來檢查由 Type 之執行個體表示的未知型別時,請使用 IsGenericType 屬性來判斷此未知型別是否為泛型。 如果此型別是泛型,則會傳回 true。 同樣地,當您檢查由 MethodInfo 類別之執行個體所表示的未知方法時,請使用 IsGenericMethod 屬性來判斷此方法是否為泛型。

這是泛型型別還是方法定義?

使用 IsGenericTypeDefinition 屬性來判斷 Type 物件是否表示泛型型別定義,並使用 IsGenericMethodDefinition 方法來判斷 MethodInfo 是否表示泛型方法定義。

泛型型別和方法定義都是建立可執行個體化之型別時所根據的樣板; .NET Framework 類別庫中的泛型型別 (例如 Dictionary<TKey, TValue>) 就是泛型型別定義。

此型別或方法為開放式還是封閉式?

如果可執行個體化之型別已經用來替代泛型型別或方法的所有型別參數 (包括所有封入型別的所有型別參數),則此泛型型別或方法為封閉式。 您只能在泛型型別為封閉式時,建立它的執行個體。 如果型別為開放式,Type.ContainsGenericParameters 屬性會傳回 true。 如果是方法,則 MethodInfo.ContainsGenericParameters 方法會執行相同的功能。

回到頁首

產生封閉式泛型型別

一旦您有泛型型別或方法定義之後,請使用 MakeGenericType 方法來建立封閉式泛型型別,或使用 MakeGenericMethod 方法為封閉式泛型方法建立 MethodInfo

取得泛型型別或方法定義

如果您擁有的開放式泛型型別或方法不是泛型型別或方法定義,您將無法建立它的執行個體,也無法提供遺漏的型別參數。 您必須要有泛型型別或方法定義; 請使用 GetGenericTypeDefinition 方法來取得泛型型別定義,或使用 GetGenericMethodDefinition 方法來取得泛型方法定義。

例如,如果您有一個表示 Dictionary<int, string> (Visual Basic 中為 Dictionary(Of Integer, String)) 的 Type 物件,而且您想要建立型別 Dictionary<string, MyClass>,您可使用 GetGenericTypeDefinition 方法來取得表示 Dictionary<TKey, TValue> 的 Type,並使用 MakeGenericType 方法來產生表示 Dictionary<int, MyClass> 的 Type

如需非泛型型別之開放式泛型型別的範例,請參閱這個主題之後的<型別參數或型別引數>。

回到頁首

檢查型別引數和型別參數

使用 Type.GetGenericArguments 方法來取得表示泛型型別之型別參數或型別引數的 Type 物件之陣列,並使用 MethodInfo.GetGenericArguments 方法來為泛型方法執行相同的處理。

一旦您知道 Type 物件表示型別參數之後,反映還可以解答許多其他的問題。 您可以判斷型別參數的來源、它的位置及它的條件約束。

型別參數或型別引數

若要判斷特定的陣列元素為型別參數或型別引數,請使用 IsGenericParameter 屬性。 如果此元素為型別參數,則 IsGenericParameter 屬性為 true。

泛型型別不需要是泛型型別定義,也可以是開放式,此時,它會混合型別引數和型別參數。 例如在下列程式碼中,類別 D 是衍生自一個型別,而此型別的建立方式,是將 D 的第一個型別參數替代 B 的第二個型別參數。

class B<T, U> {}
class D<V, W> : B<int, V> {}
Class B(Of T, U)
End Class
Class D(Of V, W)
    Inherits B(Of Integer, V)
End Class
generic<typename T, typename U> ref class B {};
generic<typename V, typename W> ref class D : B<int, V> {};

如果您取得一個表示 D<V, W> 的 Type 物件,並使用 BaseType 屬性來取得它的基底型別,則產生的 type B<int, V> 會是開放式,但不是泛型型別定義。

泛型參數的來源

泛型型別參數可能來自於您正在檢查的型別、封入型別或泛型方法。 您可利用下列方式判斷泛型型別參數的來源:

  • 首先,使用 DeclaringMethod 屬性來判斷型別參數是否來自於泛型方法。 如果此屬性值不是 null 參考 (Visual Basic 中為 Nothing),則來源為泛型方法。

  • 如果來源不是泛型方法,請使用 DeclaringType 屬性來判斷泛型型別參數所屬的泛型型別。

如果此型別參數屬於泛型方法,則 DeclaringType 屬性會傳回宣告此泛型方法的型別 (它並沒有什麼重要性)。

泛型參數的位置

在罕見的情況下,必須判斷某個型別參數在它的宣告類別之型別參數清單中的位置。 例如,假設您有一個 Type 物件,其表示上一個範例中的 B<int, V> 型別。 GetGenericArguments 方法會為您提供型別參數清單,而當您檢查 V 時,您可使用 DeclaringMethodDeclaringType 屬性來探查它的來源。 然後,您可使用 GenericParameterPosition 屬性來判斷它在型別參數清單中定義所在的位置。 在此範例中,V 在型別參數清單中定義所在的位置為 0 (零)。

基底型別和介面的條件約束

使用 GetGenericParameterConstraints 方法來取得型別參數的基底型別條件約束和介面條件約束。 陣列的元素順序並不是很重要, 如果某個元素為介面型別,則該元素表示介面條件約束。

泛型參數屬性

GenericParameterAttributes 屬性會取得 GenericParameterAttributes 值,表示型別參數的變異數 (共變數或反變數) 以及特殊條件約束。

共變數和反變數

若要判斷某個型別參數是否為共變數或反變數,請將 GenericParameterAttributes.VarianceMask 遮罩套用至 GenericParameterAttributes 屬性所傳回的 GenericParameterAttributes 值。 如果結果為 GenericParameterAttributes.None,表示型別參數是非變異的。 請參閱泛型中的共變數和反變數

特殊條件約束

若要判斷某個型別參數的特殊條件約束,請將 GenericParameterAttributes.SpecialConstraintMask 遮罩套用至 GenericParameterAttributes 屬性所傳回的 GenericParameterAttributes 值。 如果結果為 GenericParameterAttributes.None,表示沒有任何特殊條件約束。 型別參數可以限制為參考型別、不可為 Null 的實值型別,以及擁有預設建構函式。

回到頁首

不變項目

如需泛型型別反映中常用詞彙的不變條件之表格,且參閱 Type.IsGenericType。 如需與泛型方法有關的詞彙,請參閱 MethodInfo.IsGenericMethod

回到頁首

相關主題

標題

說明

HOW TO:使用反映檢視和執行個體化泛型型別

示範如何使用 TypeMethodInfo 的屬性和方法來檢查泛型型別。

.NET Framework 中的泛型

描述泛型功能以及 .NET Framework 如何支援這項功能。

HOW TO:使用反映發出定義泛型型別

示範如何使用反映發出來產生動態組件中的泛型型別。

檢視型別資訊

描述 Type 類別,並提供程式碼範例,以說明如何將 Type 與各種反映類別一起使用,以取得與建構函式、方法、欄位、屬性和事件有關的資訊。

回到頁首