Partager via


Réflexion et types génériques

Du point de vue de la réflexion, la différence entre un type générique et un type ordinaire est qu’un type générique lui a associé un ensemble de paramètres de type (s’il s’agit d’une définition de type générique) ou d’arguments de type (s’il s’agit d’un type construit). Une méthode générique diffère d’une méthode ordinaire de la même façon.

Il existe deux clés pour comprendre comment la réflexion gère les types génériques et les méthodes :

  • Les paramètres de type des définitions de type générique et des définitions de méthode générique sont représentés par des instances de la Type classe.

    Remarque

    De nombreuses propriétés et méthodes de Type ont un comportement différent lorsqu'un objet Type représente un paramètre de type générique. Ces différences sont documentées dans les articles de propriété et de méthode. Par exemple, voir IsAutoClass et DeclaringType. En outre, certains membres sont valides uniquement lorsqu’un Type objet représente un paramètre de type générique. Par exemple, consultez GetGenericTypeDefinition.

  • Si une instance de Type représente un type générique, elle inclut un tableau de types qui représentent les paramètres de type (pour les définitions de types génériques) ou les arguments de type (pour les types construits). Il en va de même pour une instance de la MethodInfo classe qui représente une méthode générique.

La réflexion fournit des méthodes telles que Type et MethodInfo, qui vous permettent d’accéder au tableau de paramètres de types et de déterminer si une instance de Type représente un paramètre de type ou un type concret.

Pour obtenir un exemple de code illustrant les méthodes décrites ici, consultez Comment : examiner et instancier des types génériques avec réflexion.

La discussion suivante suppose une connaissance de la terminologie des génériques, comme la différence entre les paramètres de type et les arguments et les types construits ouverts ou fermés. Pour plus d’informations, consultez Génériques.

S’agit-il d’un type ou d’une méthode générique ?

Lorsque vous utilisez la réflexion pour examiner un type inconnu, représenté par une instance de Type, utilisez la IsGenericType propriété pour déterminer si le type inconnu est générique. Elle retourne true si le type est générique. De même, lorsque vous examinez une méthode inconnue, représentée par une instance de la MethodInfo classe, utilisez la IsGenericMethod propriété pour déterminer si la méthode est générique.

S’agit-il d’un type générique ou d’une définition de méthode ?

Utilisez la IsGenericTypeDefinition propriété pour déterminer si un Type objet représente une définition de type générique et utilisez la IsGenericMethodDefinition méthode pour déterminer s’il MethodInfo s’agit d’une définition de méthode générique.

Les définitions de type et de méthode génériques sont les modèles à partir desquels des types instanciables sont créés. Les types génériques dans les bibliothèques .NET, tels que Dictionary<TKey,TValue>, sont des définitions de types génériques.

Le type ou la méthode est-il ouvert ou fermé ?

Un type ou une méthode générique est fermé si des types instanciables ont été remplacés par tous ses paramètres de type, y compris tous les paramètres de type de tous les types englobants. Vous ne pouvez créer qu’une instance d’un type générique s’il est fermé. La Type.ContainsGenericParameters propriété retourne true si un type est ouvert. Pour les méthodes, la MethodBase.ContainsGenericParameters méthode effectue la même fonction.

Générer des types génériques fermés

Une fois que vous avez un type générique ou une définition de méthode, utilisez la MakeGenericType méthode pour créer un type générique fermé ou la MakeGenericMethod méthode pour créer une MethodInfo méthode générique fermée.

Obtenir le type générique ou la définition de méthode

Si vous avez un type générique ouvert ou une méthode qui n’est pas un type générique ou une définition de méthode, vous ne pouvez pas créer d’instances et vous ne pouvez pas fournir les paramètres de type manquants. Vous devez avoir une définition de type ou de méthode générique. Utilisez la GetGenericTypeDefinition méthode pour obtenir la définition de type générique ou la GetGenericMethodDefinition méthode pour obtenir la définition de méthode générique.

Par exemple, si vous avez un Type objet représentant Dictionary<int, string> et que vous souhaitez créer le type Dictionary<string, MyClass>, vous pouvez utiliser la GetGenericTypeDefinition méthode pour obtenir une Type représentation Dictionary<TKey, TValue> , puis utiliser la MakeGenericType méthode pour produire une Type représentation Dictionary<int, MyClass>.

Pour obtenir un exemple de type générique ouvert qui n’est pas un type générique, consultez le paramètre type ou l’argument de type.

Examiner les arguments de type et les paramètres de type

Utilisez la Type.GetGenericArguments méthode pour obtenir un tableau d’objets Type qui représentent les paramètres de type ou les arguments de type d’un type générique et utilisez la méthode pour effectuer la MethodInfo.GetGenericArguments même opération pour une méthode générique.

Une fois que vous savez qu'un objet Type représente un paramètre de type, la réflexion peut répondre à de nombreuses questions supplémentaires. Vous pouvez déterminer la source du paramètre de type, sa position et ses contraintes.

Paramètre de type ou argument de type

Pour déterminer si un élément particulier du tableau est un paramètre de type ou un argument de type, utilisez la IsGenericParameter propriété. La IsGenericParameter propriété est true si l’élément est un paramètre de type.

Un type générique peut être ouvert sans être une définition de type générique, auquel cas il a un mélange d’arguments de type et de paramètres de type. Par exemple, dans le code suivant, la classe D dérive d’un type créé en substituant le premier paramètre de type de D pour le deuxième paramètre de type de 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

Si vous obtenez un Type objet représentant D<V, W> et utilisez la BaseType propriété pour obtenir son type de base, le résultat type B<int, V> est ouvert, mais il ne s’agit pas d’une définition de type générique.

Source d’un paramètre générique

Un paramètre de type générique peut provenir du type que vous examinez, d’un type englobant ou d’une méthode générique. Vous pouvez déterminer la source du paramètre de type générique comme suit :

  • Tout d’abord, utilisez la DeclaringMethod propriété pour déterminer si le paramètre de type provient d’une méthode générique. Si la valeur de propriété n’est pas une référence Null, la source est une méthode générique.
  • Si la source n’est pas une méthode générique, utilisez la DeclaringType propriété pour déterminer le type générique auquel appartient le paramètre de type générique.

Si le paramètre de type appartient à une méthode générique, la DeclaringType propriété retourne le type qui a déclaré la méthode générique, ce qui n’est pas pertinent.

Position d’un paramètre générique

Dans de rares cas, il est nécessaire de déterminer la position d’un paramètre de type dans la liste des paramètres de type de sa classe déclarante. Par exemple, supposons que vous ayez un Type objet représentant le B<int, V> type de l’exemple précédent. La méthode GetGenericArguments vous donne une liste d’arguments de type et, lorsque vous examinez V, vous pouvez utiliser les propriétés DeclaringMethod et DeclaringType pour découvrir l’origine de celle-ci. Vous pouvez ensuite utiliser la GenericParameterPosition propriété pour déterminer sa position dans la liste des paramètres de type où elle a été définie. Dans cet exemple, V se trouve à la position 0 (zéro) dans la liste des paramètres de type où elle a été définie.

Contraintes de type de base et d’interface

Utilisez la méthode pour obtenir la GetGenericParameterConstraints contrainte de type de base et les contraintes d’interface d’un paramètre de type. L’ordre des éléments du tableau n’est pas significatif. Un élément représente une contrainte d’interface s’il s’agit d’un type d’interface.

Attributs de paramètre générique

La GenericParameterAttributes propriété obtient une GenericParameterAttributes valeur qui indique la variance (covariance ou contravariance) et les contraintes spéciales d’un paramètre de type.

Covariance et contravariance

Pour déterminer si un paramètre de type est covariant ou contravariant, appliquez le GenericParameterAttributes.VarianceMask masque à la GenericParameterAttributes valeur retournée par la GenericParameterAttributes propriété. Si le résultat est GenericParameterAttributes.None, le paramètre de type est invariant. Pour plus d’informations, consultez Covariance et Contravariance.

Contraintes spéciales

Pour déterminer les contraintes spéciales d’un paramètre de type, appliquez le GenericParameterAttributes.SpecialConstraintMask masque à la GenericParameterAttributes valeur retournée par la GenericParameterAttributes propriété. Si le résultat est GenericParameterAttributes.None, il n’existe aucune contrainte spéciale. Un paramètre de type peut être contraint d’être un type référence, d’être un type valeur non nullable et d’avoir un constructeur sans paramètre.

Invariants

Pour obtenir une table des conditions invariantes pour les termes courants en réflexion pour les types génériques, consultez Type.IsGenericType. Pour plus d’informations sur les termes relatifs aux méthodes génériques, consultez MethodBase.IsGenericMethod.