Compartir a través de


Reflexión y tipos genéricos

Desde el punto de vista de la reflexión, la diferencia entre un tipo genérico y un tipo ordinario es que un tipo genérico se ha asociado a él un conjunto de parámetros de tipo (si es una definición de tipo genérico) o argumentos de tipo (si es un tipo construido). Un método genérico difiere de un método normal de la misma manera.

Hay dos claves para comprender cómo la reflexión controla los tipos y métodos genéricos:

  • Los parámetros de tipo de definiciones de tipos genéricos y definiciones de método genérico se representan mediante instancias de la Type clase .

    Nota:

    Muchas propiedades y métodos de Type tienen un comportamiento diferente cuando un Type objeto representa un parámetro de tipo genérico. Estas diferencias se documentan en los artículos de propiedades y métodos. Por ejemplo, vea IsAutoClass y DeclaringType. Además, algunos miembros solo son válidos cuando un Type objeto representa un parámetro de tipo genérico. Por ejemplo, vea GetGenericTypeDefinition.

  • Si una instancia de Type representa un tipo genérico, incluye una matriz de tipos que representan los parámetros de tipo (para definiciones de tipos genéricos) o los argumentos de tipo (para los tipos construidos). Lo mismo sucede con una instancia de la MethodInfo clase que representa un método genérico.

La reflexión proporciona métodos de Type y MethodInfo que permiten tener acceso a la matriz de parámetros de tipo y determinar si una instancia de Type, representa un parámetro de tipo o un tipo real.

Para obtener código de ejemplo que muestra los métodos descritos aquí, vea Cómo: Examinar e crear instancias de tipos genéricos con reflexión.

En la siguiente explicación se supone que está familiarizado con la terminología de los genéricos, como la diferencia entre los parámetros de tipo y los argumentos y los tipos construidos abiertos o cerrados. Para obtener más información, vea Genéricos.

¿Es un tipo o método genérico?

Cuando se usa la reflexión para examinar un tipo desconocido, representado por una instancia de Type, use la IsGenericType propiedad para determinar si el tipo desconocido es genérico. Devuelve true si el tipo es genérico. Del mismo modo, al examinar un método desconocido, representado por una instancia de la MethodInfo clase, use la IsGenericMethod propiedad para determinar si el método es genérico.

¿Se trata de un tipo genérico o una definición de método?

Utilice la IsGenericTypeDefinition propiedad para determinar si un Type objeto representa una definición de tipo genérico y usa el IsGenericMethodDefinition método para determinar si representa MethodInfo una definición de método genérico.

Las definiciones de método y tipo genérico son las plantillas desde las que se crean tipos instanciables. Los tipos genéricos de las bibliotecas de .NET, como Dictionary<TKey,TValue>, son definiciones de tipos genéricos.

¿El tipo o el método están abiertos o cerrados?

Un tipo o método genérico está cerrado si se han sustituido los tipos instanciables para todos sus parámetros de tipo, incluidos todos los parámetros de tipo de todos los tipos contenedores. Solo puede crear una instancia de un tipo genérico si está cerrada. La Type.ContainsGenericParameters propiedad devuelve true si un tipo está abierto. En el caso de los métodos, el MethodBase.ContainsGenericParameters método realiza la misma función.

Generación de tipos genéricos cerrados

Una vez que tenga una definición de método o tipo genérico, use el MakeGenericType método para crear un tipo genérico cerrado o el MakeGenericMethod método para crear un MethodInfo para un método genérico cerrado.

Obtención de la definición de método o tipo genérico

Si tiene un tipo o método genérico abierto que no es un tipo genérico o una definición de método, no puede crear instancias de él y no puede proporcionar los parámetros de tipo que faltan. Debe tener una definición de tipo o método genérico. Use el GetGenericTypeDefinition método para obtener la definición de tipo genérico o el GetGenericMethodDefinition método para obtener la definición del método genérico.

Por ejemplo, si tiene un Type objeto que representa Dictionary<int, string> y desea crear el tipo Dictionary<string, MyClass>, puede usar el GetGenericTypeDefinition método para obtener una Type representación Dictionary<TKey, TValue> y, a continuación, usar el MakeGenericType método para generar un Type objeto que represente Dictionary<int, MyClass>.

Para obtener un ejemplo de un tipo genérico abierto que no es un tipo genérico, vea Parámetro de tipo o argumento de tipo.

Examen de argumentos de tipo y parámetros de tipo

Utilice el Type.GetGenericArguments método para obtener una matriz de Type objetos que representan los parámetros de tipo o argumentos de tipo de un tipo genérico y use el MethodInfo.GetGenericArguments método para hacer lo mismo para un método genérico.

Una vez que sepa que un Type objeto representa un parámetro de tipo, la reflexión puede responder muchas preguntas adicionales. Puede determinar el origen del parámetro de tipo, su posición y sus restricciones.

Parámetro de tipo o argumento de tipo

Para determinar si un elemento determinado de la matriz es un parámetro de tipo o un argumento de tipo, use la IsGenericParameter propiedad . La IsGenericParameter propiedad es true si el elemento es un parámetro de tipo.

Un tipo genérico se puede abrir sin ser una definición de tipo genérico, en cuyo caso tiene una combinación de argumentos de tipo y parámetros de tipo. Por ejemplo, en el código siguiente, la clase D deriva de un tipo creado sustituyendo el primer parámetro de tipo de D por el segundo parámetro de tipo 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 obtiene un Type objeto que representa D<V, W> y usa la BaseType propiedad para obtener su tipo base, el resultado type B<int, V> está abierto, pero no es una definición de tipo genérico.

Origen de un parámetro genérico

Un parámetro de tipo genérico puede provenir del tipo que está examinando, de un tipo envolvente o de un método genérico. Puede determinar el origen del parámetro de tipo genérico de la siguiente manera:

  • En primer lugar, use la DeclaringMethod propiedad para determinar si el parámetro de tipo procede de un método genérico. Si el valor de la propiedad no es una referencia nula, el origen es un método genérico.
  • Si el origen no es un método genérico, use la propiedad para determinar el DeclaringType tipo genérico al que pertenece el parámetro de tipo genérico.

Si el parámetro de tipo pertenece a un método genérico, la DeclaringType propiedad devuelve el tipo que declaró el método genérico, que es irrelevante.

Posición de un parámetro genérico

En raras situaciones, es necesario determinar la posición de un parámetro de tipo en la lista de parámetros de tipo de su clase declarante. Por ejemplo, supongamos que tiene un Type objeto que representa el B<int, V> tipo del ejemplo anterior. El GetGenericArguments método proporciona una lista de argumentos de tipo y, al examinar V , puede usar las DeclaringMethod propiedades y DeclaringType para detectar dónde procede. A continuación, puede usar la GenericParameterPosition propiedad para determinar su posición en la lista de parámetros de tipo donde se definió. En este ejemplo, V está en la posición 0 (cero) de la lista de parámetros de tipo donde se definió.

Tipo base y restricciones de interfaz

Use el GetGenericParameterConstraints método para obtener la restricción de tipo base y las restricciones de interfaz de un parámetro de tipo. El orden de los elementos de la matriz no es significativo. Un elemento representa una restricción de interfaz si es un tipo de interfaz.

Atributos de parámetro genéricos

La GenericParameterAttributes propiedad obtiene un GenericParameterAttributes valor que indica la varianza (covarianza o contravarianza) y las restricciones especiales de un parámetro de tipo.

Covarianza y contravarianza

Para determinar si un parámetro de tipo es covariante o contravariante, aplique la GenericParameterAttributes.VarianceMask máscara al GenericParameterAttributes valor devuelto por la GenericParameterAttributes propiedad . Si el resultado es GenericParameterAttributes.None, el parámetro type es invariable. Para obtener más información, vea Covarianza y Contravarianza.

Restricciones especiales

Para determinar las restricciones especiales de un parámetro de tipo, aplique la máscara GenericParameterAttributes.SpecialConstraintMask al valor GenericParameterAttributes que devuelva la propiedad GenericParameterAttributes. Si el resultado es GenericParameterAttributes.None, no hay restricciones especiales. Un parámetro de tipo se puede restringir para que sea un tipo de referencia, que sea un tipo de valor que no acepta valores NULL y que tenga un constructor sin parámetros.

Invariantes

Para obtener una tabla de las condiciones invariables para los términos comunes en reflexión para tipos genéricos, vea Type.IsGenericType. Para obtener términos adicionales relacionados con métodos genéricos, vea MethodBase.IsGenericMethod.