Reflektion und generische Typen
Aus Sicht der Reflexion besteht der Unterschied zwischen einem generischen und einem gewöhnlichen Typ darin, dass ein generischer Typ mit einem Typparameterset (bei einer generischen Typdefinition) oder mit Typargumenten (bei einem konstruierten Typ) verknüpft ist. Auf dieselbe Art unterscheidet sich eine generische Methode von einer normalen Methode.
Es gibt zwei wichtige Schlüssel für das Verständnis des Umgangs von Reflektion mit generischen Typen und Methoden:
Die Typparameter der generischen Typdefinitionen und generischen Methodendefinitionen werden durch Instanzen der Type -Klasse dargestellt.
Hinweis
Viele Eigenschaften und Methoden des Type -Objekts weisen ein anderes Verhalten auf, wenn ein Type -Objekt einen generischen Typparameter darstellt. Diese Unterschiede werden in den Artikeln zu Eigenschaften und Methoden erläutert. Beispielsweise unter IsAutoClass und DeclaringType. Darüber hinaus sind einige Member nur gültig, wenn ein Type -Objekt einen generischen Typparameter darstellt. Ein Beispiel finden Sie unter GetGenericTypeDefinition.
Wenn eine Instanz des Type -Objekts einen generischen Typ darstellt, enthält es ein Array von Typen, das die Typparameter (bei generischen Typdefinitionen) oder die Typargumente (bei konstruierten Typen) darstellt. Gilt auch für eine Instanz der MethodInfo -Klasse, die eine generische Methode darstellt.
Reflektion stellt Type- und MethodInfo-Methoden bereit, mit denen Sie auf das Array von Typparametern zugreifen und ermitteln können, ob eine Type-Instanz einen Typparameter oder einen tatsächlichen Typ darstellt.
Beispielcode, der die hier erörterten Methoden veranschaulicht, finden Sie unter Vorgehensweise: Untersuchen und Instanziieren von generischen Typen mit Reflektion.
Bei der folgenden Erläuterung wird davon ausgegangen, dass Sie mit der Terminologie von Generics vertraut sind, d. h. Sie kennen beispielsweise den Unterschied zwischen Typparametern und Typargumenten sowie zwischen offenen und geschlossenen konstruierten Typen. Weitere Informationen finden Sie unter Generics.
Ist dies ein generischer Typ oder eine generische Methode?
Verwenden Sie beim Überprüfen eines unbekannten durch eine Instanz der Type-Klasse dargestellten Typs die IsGenericType -Eigenschaft, um zu ermitteln, ob es sich beim unbekannten Typ um einen generischen Typ handelt. Die Eigenschaft gibt true
zurück, wenn es sich um einen generischen Typ handelt. Verwenden Sie dementsprechend beim Überprüfen einer unbekannten durch eine Instanz der MethodInfo -Klasse dargestellten Methode die IsGenericMethod -Eigenschaft, um zu ermitteln, ob es sich bei der unbekannten Methode um eine generische Methode handelt.
Ist dies eine generische Typ- oder Methodendefinition?
Mit der IsGenericTypeDefinition -Eigenschaft können Sie bestimmen, ob ein Type -Objekt eine generische Typdefinition darstellt, und mit der IsGenericMethodDefinition -Methode, ob ein MethodInfo -Objekt eine generische Methodendefinition darstellt.
Generische Typ- und Methodendefinitionen sind Vorlagen, aus denen instanziierbare Typen erstellt werden. Generische Typen in den .NET-Bibliotheken, z. B. Dictionary<TKey,TValue>, verfügen über generische Typdefinitionen.
Ist der Typ bzw. die Methode offen oder geschlossen?
Ein generischer Typ oder eine generische Methode ist geschlossen, wenn alle Typparameter, u. a. Typparameter aller einschließenden Typen durch instanziierbare Typen ersetzt wurden. Sie können nur dann eine Instanz eines generischen Typs erstellen, wenn er geschlossen ist. Die Type.ContainsGenericParameters -Eigenschaft gibt true
zurück, wenn ein Typ offen ist. Bei Methoden erfüllt die MethodBase.ContainsGenericParameters -Methode die gleiche Funktion.
Generieren geschlossener generischer Typen
Wenn Sie bereits über eine generische Typ- oder Methodendefinition verfügen, können Sie mit der MakeGenericType -Methode einen geschlossenen generischen Typ erstellen oder mit der MakeGenericMethod -Methode ein MethodInfo -Objekt für eine geschlossene generische Methode erstellen.
Abrufen der generischen Typ- oder Methodendefinition
Wenn Sie über einen offenen generischen Typ oder eine offene generische Methode verfügen, der bzw. die keine generische Typ- bzw. Methodendefinition ist, können Sie keine Instanzen davon erstellen und keine fehlenden Typparameter bereitstellen. Sie müssen über eine generische Typ- oder Methodendefinition verfügen. Verwenden Sie zum Abrufen der generischen Typdefinition die GetGenericTypeDefinition -Methode oder die GetGenericMethodDefinition -Methode zum Abrufen der generischen Methodendefinition.
Wenn Sie ein Type-Objekt haben, das ein Dictionary<int, string>
-Objekt darstellt, und den Dictionary<string, MyClass>
-Typ erstellen möchten, können Sie mit der GetGenericTypeDefinition-Methode ein Type--Objekt abrufen, das Dictionary<TKey, TValue>
darstellt, und dann mit der MakeGenericType-Methode ein Type-Objekt erzeugen, das Dictionary<int, MyClass>
darstellt.
Ein Beispiel für einen offenen generischen Typ, der kein generischer Typ ist, finden Sie unter Typparameter oder Typargument.
Überprüfen von Typargumenten und Typparametern
Verwenden Sie zum Abrufen eines Arrays von Type.GetGenericArguments -Objekten, das die Typparameter oder Typargumente eines generischen Typs darstellt, die Type -Methode und die MethodInfo.GetGenericArguments -Methode, um diesen Vorgang für eine generische Methode auszuführen.
Wenn Sie wissen, das ein Type -Objekt einen Typparameter darstellt, kann Reflektion eine Antwort auf viele weitere Fragen bieten. Sie können die Quelle, Position und Einschränkungen des Typparameters bestimmen.
Typparameter oder Typargument
Verwenden Sie die IsGenericParameter -Eigenschaft zum Bestimmen, ob ein bestimmtes Element des Arrays ein Typparameter oder Typargument ist. Die IsGenericParameter -Eigenschaft ist true
, wenn das Element ein Typparameter ist.
Bei einem generischen Typ kann es sich auch um einen offenen Typ handeln, wenn dieser keine generische Typdefinition ist. In diesem Fall verfügt er über eine Mischung aus Typargumenten und Typparametern. Im folgenden Code leitet sich beispielsweise die D
-Klasse von einem Typ ab, der durch das Ersetzen des zweiten Typparameters von D
mit dem ersten Typparameter von B
erstellt wurde.
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> {};
Wenn Sie ein Type-Objekt erhalten, das ein D<V, W>
darstellt, und die BaseType-Eigenschaft zum Abrufen des Basistyps verwenden, ist das resultierende type B<int, V>
-Objekt ein offener Typ, der jedoch keine generische Typdefinition darstellt.
Quelle eines generischen Parameters
Ein generischer Typparameter kann von einem überprüften Typ, einschließenden Typ oder von einer generischen Methode stammen. Die Quelle des generischen Typparameters kann folgendermaßen bestimmt werden:
- Verwenden Sie zuerst die DeclaringMethod -Eigenschaft, um zu ermitteln, ob der Typparameter von einer generischen Methode stammt. Wenn der Eigenschaftswert kein NULL-Verweis ist, dann ist die Quelle eine generische Methode.
- Wenn die Quelle keine generische Methode ist, verwenden Sie die DeclaringType -Eigenschaft zum Bestimmen des generischen Typs, zu dem der generische Typparameter gehört.
Wenn der Typparameter zu einer generischen Methode gehört, gibt die DeclaringType -Eigenschaft den Typ zurück, der die generische irrelevante Methode deklariert hat.
Position eines generischen Parameters
In seltenen Fällen ist es erforderlich, die Position eines Typparameters in der Typparameterliste seiner deklarierenden Klasse zu ermitteln. Angenommen Sie verfügen über ein Type -Objekt, das den B<int, V>
-Typ aus dem vorherigen Beispiel darstellt. Mit der GetGenericArguments -Methode erhalten Sie eine Liste von Typargumenten. Beim Überprüfen des V
-Objekts können Sie dann die DeclaringMethod - und DeclaringType -Eigenschaften verwenden, um die Herkunft dieses Objekts zu bestimmen. Sie können dann mithilfe der GenericParameterPosition -Eigenschaft seine Position in der Typparameterliste ermitteln, in dem es definiert wurde. In diesem Beispiel befindet sich V
an Position 0 (null) in der Typparameterliste, in der das Objekt definiert wurde.
Basistyp und Schnittstelleneinschränkungen
Verwenden Sie die GetGenericParameterConstraints -Methode, um die Basistypeinschränkung und Schnittstelleneinschränkungen eines Typparameters abzurufen. Die Reihenfolge der Elemente des Arrays spielt keine Rolle. Ein Element stellt eine Schnittstelleneinschränkung dar, wenn es ein Schnittstellentyp ist.
Generische Parameterattribute
Die GenericParameterAttributes -Eigenschaft ruft einen GenericParameterAttributes -Wert ab, der die Varianz (Kovarianz oder Kontravarianz) und die besonderen Einschränkungen eines Typparameters angibt.
Kovarianz und Kontravarianz
Zum Bestimmen, ob ein Typparameter kovariant oder kontravariant ist, können Sie die GenericParameterAttributes.VarianceMask -Maske auf den von der GenericParameterAttributes -Eigenschaft zurückgegebenen GenericParameterAttributes -Wert anwenden. Wenn das Ergebnis GenericParameterAttributes.Noneist, ist der Typparameter invariant. Weitere Informationen finden Sie unter Kovarianz und Kontravarianz.
Besondere Einschränkungen
Wenden Sie zum Bestimmen von besonderen Einschränkungen eines Typparameters die GenericParameterAttributes.SpecialConstraintMask -Maske auf den von der GenericParameterAttributes -Eigenschaft zurückgegebenen GenericParameterAttributes -Wert an. Wenn das Ergebnis GenericParameterAttributes.Noneist, gibt es keine besonderen Einschränkungen. Die Einschränkungen eines Typparameters können ein Verweistyp, ein Werttyp, der keine NULL-Werte zulässt, und ein parameterloser Konstruktor sein.
Invarianten
Eine Tabelle der invarianten Bedingungen für allgemeine Begriffe in Reflektion für generische Typen finden Sie unter Type.IsGenericType. Weitere Begriffe, die im Zusammenhang mit generischen Methoden stehen, finden Sie unter MethodBase.IsGenericMethod.