El método MakeGenericType permite escribir código que asigna tipos específicos a los parámetros de tipo de una definición de tipo genérico, por lo que crea un objeto Type que representa un tipo construido determinado. Puede utilizar este objeto Type para crear instancias en tiempo de ejecución del tipo construido.
Los tipos construidos con el método MakeGenericType pueden ser abiertos; es decir, algunos de sus argumentos de tipo pueden ser parámetros de tipo de métodos o tipos genéricos envolventes. Podría utilizar dichos tipos construidos abiertos al emitir ensamblados dinámicos. Por ejemplo, considere las clases Base y Derived en el código siguiente.
Public Class Base(Of T, U)
End Class
Public Class Derived(Of V)
Inherits Base(Of Integer, V)
End Class
public class Base<T, U> { }
public class Derived<V> : Base<int, V> { }
generic<typename T, typename U>
public ref class Base { };
generic<typename V>
public ref class Derived : Base<int, V> { };
Para generar la clase Derived en un ensamblado dinámico, es necesario construir su tipo base. Para ello, llame al método MakeGenericType en un objeto Type que represente la clase Base y utilice los argumentos de tipo genérico Int32 y el parámetro de tipo V de la clase Derived. Dado que los tipos y los parámetros de tipo genérico se representan mediante objetos Type, se puede pasar al método MakeGenericType una matriz que contenga los dos.
Nota |
|---|
| Un tipo construido como Base<int, V> resulta útil al emitir código, pero no se puede llamar al método MakeGenericType en este tipo porque no es una definición de tipo genérico. Para crear un tipo construido cerrado del que se pueden crear instancias, primero llame al método GetGenericTypeDefinition a fin de obtener un objeto Type que represente una definición de tipo genérico y, luego, llame al método MakeGenericType con los argumentos de tipo deseados. |
El objeto Type devuelto por el método MakeGenericType es el mismo que el objeto Type que se obtiene al llamar al método GetType del tipo construido resultante o al método GetType de cualquier tipo construido que se haya creado a partir de la misma definición de tipo genérico con el mismo tipo de argumentos.
Nota |
|---|
| Una matriz de tipos genéricos no es propiamente un tipo genérico. No se puede llamar al método MakeGenericType en un tipo de matriz como C<T>[] (Dim ac() As C(Of T) en Visual Basic). Si desea construir un tipo genérico cerrado a partir de C<T>[], llame a GetElementType para obtener la definición de tipo genérico C<T>; llame a MakeGenericType en la definición de tipo genérico para crear el tipo construido y, por último, llame al método MakeArrayType en el tipo construido para crear el tipo de matriz. Lo anterior también se aplica a los tipos de puntero y a los tipos ref (ByRef en Visual Basic). |
Si desea obtener una lista de las condiciones invariables para términos que se utilizan en la reflexión genérica, vea los comentarios de la propiedad IsGenericType.
Tipos anidados
Si se define un tipo genérico utilizando C# , C++ o Visual Basic, todos sus tipos anidados son genéricos. Esto se cumple incluso cuando los tipos anidados no poseen ningún parámetro de tipo propio, porque los tres lenguajes incluyen los parámetros de tipo de los tipos envolventes en las listas de parámetros de tipo de los tipos anidados. Considere las clases siguientes:
Public Class Outermost(Of T)
Public Class Inner(Of U)
Public Class Innermost1(Of V)
End Class
Public Class Innermost2
End Class
End Class
End Class
public class Outermost<T>
{
public class Inner<U>
{
public class Innermost1<V> {}
public class Innermost2 {}
}
}
generic<typename T> public ref class Outermost
{
public:
generic<typename U> ref class Inner
{
public:
generic<typename V> ref class Innermost1 {};
ref class Innermost2 {};
};
};
La lista de parámetros de tipo de la clase anidada Inner tiene dos parámetros de tipo, T y U, siendo el primero el parámetro de tipo de su clase envolvente. De manera similar, la lista de parámetros de tipo de la clase anidada Innermost1 tiene tres parámetros de tipo, T, U y V, proviniendo T y U de sus clases envolventes. La clase anidada Innermost2 tiene dos parámetros de tipo, T y U, que provienen de sus clases envolventes.
Si la lista de parámetros del tipo envolvente tiene más de un parámetro de tipo, todos los parámetros de tipo se incluyen en orden en la lista de parámetros de tipo del tipo anidado.
Para construir un tipo genérico a partir de la definición de tipo genérico para un tipo anidado, llame al método MakeGenericType con la matriz formada al concatenar las matrices de argumentos de todos los tipos envolventes, comenzando por el tipo genérico exterior y finalizando por la matriz de argumentos del tipo anidado si éste tiene sus propios parámetros de tipo. Para crear una instancia de Innermost1, llame al método MakeGenericType con una matriz que contenga tres tipos, que se van a asignar a T, U y V. Para crear una instancia de Innermost2, llame al método MakeGenericType con una matriz que contenga dos tipos, que se van a asignar a T y U.
El lenguaje propaga los parámetros de tipo de los tipos envolventes de esta manera, de modo que puede utilizar los parámetros de tipo de un tipo envolvente para definir los campos de los tipos anidados. De lo contrario, los parámetros de tipo no quedarán dentro del ámbito en los tipos anidados. Es posible definir tipos anidados sin propagar los parámetros de tipo de los tipos envolventes mediante la emisión de código en los ensamblados dinámicos o utilizando Ensamblador de MSIL (Ilasm.exe). Consideremos el código siguiente para el ensamblador de MSIL:
.class public Outer<T> {
.class nested public Inner<U> {
.class nested public Innermost {
}
}
} En este ejemplo, no es posible definir un campo de tipo T o U en la clase Innermost, puesto que esos parámetros de tipo están fuera de ámbito. En el código de ensamblador siguiente se definen clases anidadas que se comportan igual que si estuvieran definidas en C++, Visual Basic y C#:
.class public Outer<T> {
.class nested public Inner<T, U> {
.class nested public Innermost<T, U, V> {
}
}
} Puede utilizar Desensamblador de MSIL (Ildasm.exe) para examinar clases anidadas definidas en los lenguajes de alto nivel y observar este esquema de denominación.