反映和泛型型別

從反映的觀點來看,泛型型別與一般型別之間的差異在於泛型型別與一組類型參數相關聯(如果是泛型型別定義)或類型自變數(如果是建構型別)。 泛型方法與一般方法的差異也如同上述。

了解反映如何處理泛型類型和方法有兩種方式:

  • Type 類別的執行個體,代表泛型類型定義與泛型方法定義的類型參數。

    注意

    Type 物件代表泛型類型參數時,許多 Type 的屬性與方法會有不同的行為。 這些差異記載於 屬性和方法文章中。 如需範例,請參閱 IsAutoClassDeclaringType。 此外,部分成員僅限於 Type 物件代表泛型類型參數時才有效。 如需範例,請參閱 GetGenericTypeDefinition

  • 如果 Type 的執行個體代表泛型類型,則其包含一個代表類型參數 (若是泛型類型定義) 或代表類型引數 (若是建構類型) 的類型陣列。 上述同樣適用於代表泛型方法之 MethodInfo 類別的執行個體。

反映提供允許您存取類型參數陣列之 TypeMethodInfo 的方法,並決定 Type 的執行個體是否代表類型參數或實際的類型。

如需示範此處所探論之方法的程式碼範例,請參閱如何:使用反映檢視和執行個體化泛型型別

下列討論假設您熟悉泛型術語,例如類型參數與引數之間的差異,以及引數與開放式或封閉式的建構類型。 如需詳細資訊,請參閱泛型

這是泛型類型或方法嗎?

當您使用反映來查看未知的類型 (以 Type的執行個體表示) 時,請使用 IsGenericType 屬性來決定未知類型是否為泛型。 如果類型為泛型,其將傳回 true 。 同樣地,查看未知的方法 (以 MethodInfo 類別的執行個體表示) 時,請使用 IsGenericMethod 屬性來決定方法是否為泛型。

這是泛型類型或方法定義嗎?

使用 IsGenericTypeDefinition 屬性來決定 Type 物件是否代表泛型類型定義,並使用 IsGenericMethodDefinition 方法來決定 MethodInfo 是否代表泛型方法定義。

泛型類型與方法定義為建立執行個體類型的範本。 .NET 連結庫中的泛型型別,例如 Dictionary<TKey,TValue>, 是泛型型別定義。

類型或方法是否開啟或關閉?

如果可具現化類型已取代其所有類型參數 (包括所有封入類型的類型參數),則泛型類型或方法為封閉式。 只有在關閉泛型類型時,您才能建立泛型類型的實例。 如果類型為開放式,則 Type.ContainsGenericParameters 屬性會傳回 true 。 若是方法,則 MethodBase.ContainsGenericParameters 方法會執行相同的函式。

產生封閉式泛型類型

若您有泛型類型或方法定義,使用 MakeGenericType 方法可建立封閉式泛型類型,而使用 MakeGenericMethod 方法則會為封閉式泛型方法建立 MethodInfo

取得泛型類型或方法定義

如果您有不是泛型型別或方法定義的開放式泛型型別或方法,則無法建立它的實例,而且無法提供遺漏的類型參數。 您必須具有泛型類型或泛型定義。 使用 GetGenericTypeDefinition 方法可取得泛型類型定義,而使用 GetGenericMethodDefinition 方法則可取得泛型方法定義。

例如,如果您有代表 TypeDictionary<int, string> 的物件,而且想要建立型 Dictionary<string, MyClass>別,您可以使用 GetGenericTypeDefinition 方法取得 Type 表示 Dictionary<TKey, TValue> ,然後使用 MakeGenericType 方法產生 Type 代表 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> {};

如果您取得Type代表 的物件並使用 BaseType 屬性來取得其基底類型,則結果type B<int, V>會開啟,但不是泛型D<V, W>型別定義。

泛型參數的來源

泛型類型參數可能來自於目前正在檢查的類型、封入類型,或是來自泛型方法。 您可以透過下列方式來判斷泛型類型參數的來源:

  • 首先,使用 DeclaringMethod 屬性來判斷類型參數是否來自泛型方法。 如果屬性值不是 Null 參考,則來源是泛型方法。
  • 如果來源不是泛型方法,請使用 DeclaringType 屬性來判斷泛型類型參數所屬的泛型類型。

如果類型參數屬於泛型的方法, DeclaringType 屬性會傳回原先宣告泛型方法但不相關的類型。

泛型參數的位置

在罕見的情況下,必須判斷類型參數在其宣告類別的類型參數清單中的位置。 例如,假設您有前述範例中代表 Type 類型的 B<int, V> 物件。 GetGenericArguments 方法提供有類型引數的清單,且在查看 V 時,您可以使用 DeclaringMethodDeclaringType 屬性以探索其來自何處。 您可以使用 GenericParameterPosition 屬性來判斷其定義所在之類型參數清單中的位置。 在此範例中, V 位於其定義所在之類型參數清單中的位置 0 (零)。

基底類型和介面條件約束

使用 GetGenericParameterConstraints 方法,以取得基底類型條件約束與類型參數的介面條件約束。 陣列元素的順序並不重要。 如果專案是介面類型,則表示介面條件約束。

泛型參數屬性

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

共變數和反變數

若要判斷類型參數是共變數或是反變數,請套用 GenericParameterAttributes.VarianceMask 遮罩至由 GenericParameterAttributes 屬性所傳回的 GenericParameterAttributes 值。 如果結果為 GenericParameterAttributes.None,則類型參數為非變異值。 如需詳細資訊,請參閱 Covariance and Contravariance (共變數和反變數 (C# 和 Visual Basic))。

特殊條件約束

若要判斷類型參數的特殊條件約束,請套用 GenericParameterAttributes.SpecialConstraintMask 遮罩至 GenericParameterAttributes 屬性所傳回的 GenericParameterAttributes 值。 如果結果是 GenericParameterAttributes.None,則沒有特殊條件約束。 型別參數可以限制為參考型別、非 Null 實值型別,以及具有無參數建構函式。

非變異值

若要了解反映中泛型類型非變異條件hapi 一般條款表,請參閱 Type.IsGenericType。 與泛型方法相關的其他條款,請參閱 MethodBase.IsGenericMethod