Método System.Type.MakeGenericType
En este artículo se proporcionan comentarios adicionales a la documentación de referencia de esta API.
El MakeGenericType método permite escribir código que asigna tipos específicos a los parámetros de tipo de una definición de tipo genérico, creando así un Type objeto que representa un tipo construido en particular. Puede usar este Type objeto para crear instancias en tiempo de ejecución del tipo construido.
Los tipos construidos con MakeGenericType se pueden abrir, es decir, algunos de sus argumentos de tipo pueden ser parámetros de tipo de métodos o tipos genéricos envolventes. Puede usar estos tipos construidos abiertos al emitir ensamblados dinámicos. Por ejemplo, considere las clases Base
y Derived
en el código siguiente.
public class Base<T, U> { }
public class Derived<V> : Base<int, V> { }
type Base<'T, 'U>() = class end
type Derived<'V>() = inherit Base<int, 'V>()
Public Class Base(Of T, U)
End Class
Public Class Derived(Of V)
Inherits Base(Of Integer, V)
End Class
Para generar Derived
en un ensamblado dinámico, es necesario construir su tipo base. Para ello, llame al MakeGenericType método en un Type objeto que representa la clase Base
, mediante los argumentos Int32 de tipo genérico y el parámetro V
de tipo de Derived
. Dado que los tipos y los parámetros de tipo genérico se representan mediante Type objetos , se puede pasar una matriz que contenga ambos al MakeGenericType método .
Nota:
Un tipo construido como Base<int, V>
es útil al emitir código, pero no se puede llamar al MakeGenericType método en este tipo porque no es una definición de tipo genérico. Para crear un tipo construido cerrado que se pueda crear una instancia, primero llame al GetGenericTypeDefinition método para obtener un Type objeto que represente la definición de tipo genérico y, a continuación, llame a MakeGenericType con los argumentos de tipo deseados.
El Type objeto devuelto por MakeGenericType es el mismo que el Type obtenido llamando al GetType método del tipo construido resultante o al GetType método de cualquier tipo construido creado a partir de la misma definición de tipo genérico mediante los mismos argumentos de tipo.
Nota:
Una matriz de tipos genéricos no es un tipo genérico. No se puede llamar a MakeGenericType en un tipo de matriz como C<T>[]
(Dim ac() As C(Of T)
en Visual Basic). Para construir un tipo genérico cerrado a partir de C<T>[]
, llame GetElementType a para obtener la definición C<T>
de tipo genérico ; llame MakeGenericType a en la definición de tipo genérico para crear el tipo construido y, por último, llame al MakeArrayType método en el tipo construido para crear el tipo de matriz. Lo mismo sucede con los tipos y ref
tipos de puntero (ByRef
en Visual Basic).
Para obtener una lista de las condiciones invariables para los términos usados en la reflexión genérica, vea los comentarios de la propiedad IsGenericType.
Tipos anidados
Si se define un tipo genérico mediante C#, C++o Visual Basic, sus tipos anidados son todos genéricos. Esto es cierto incluso si los tipos anidados no tienen parámetros de tipo propios, ya que los tres lenguajes incluyen los parámetros de tipo de tipos envolventes en las listas de parámetros de tipo de tipos anidados. Tenga en cuenta las siguientes clases:
public class Outermost<T>
{
public class Inner<U>
{
public class Innermost1<V> {}
public class Innermost2 {}
}
}
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
La lista de parámetros de tipo de la clase Inner
anidada tiene dos parámetros de tipo y T
U
, el primero de los cuales es el parámetro de tipo de su clase envolvente. Del mismo modo, la lista de parámetros de tipo de la clase Innermost1
anidada tiene tres parámetros de tipo, T
, U
y V
, con T
y U
procedentes de sus clases envolventes. La clase Innermost2
anidada tiene dos parámetros de tipo, T
y U
, que proceden 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 en orden se incluyen 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 MakeGenericType método con la matriz formada mediante la concatenación de las matrices de argumentos de tipo de todos los tipos envolventes, empezando por el tipo genérico más externo y finalizando con la matriz de argumentos de tipo del propio tipo anidado, si tiene parámetros de tipo propios. Para crear una instancia de Innermost1
, llame al MakeGenericType método con una matriz que contenga tres tipos, que se asignarán a T, U y V. Para crear una instancia de Innermost2
, llame al MakeGenericType método con una matriz que contenga dos tipos, que se asignarán a T y U.
Los lenguajes propagan los parámetros de tipo de tipos envolventes de esta manera para poder usar los parámetros de tipo de un tipo envolvente para definir campos de tipos anidados. De lo contrario, los parámetros de tipo no estarían en el ámbito dentro de los cuerpos de los tipos anidados. Es posible definir tipos anidados sin propagar los parámetros de tipo de tipos envolventes, emitiendo código en ensamblados dinámicos o usando el Ilasm.exe (ensamblador de IL). Tenga en cuenta el código siguiente para el ensamblador de CIL:
.class public Outer<T> {
.class nested public Inner<U> {
.class nested public Innermost {
}
}
}
En este ejemplo, no es posible definir un campo de tipo o U
en la clase Innermost
, porque esos parámetros de tipo T
no están en el ámbito. El código del ensamblador siguiente define clases anidadas que se comportan de la manera en que se definirían en C++, Visual Basic y C#:
.class public Outer<T> {
.class nested public Inner<T, U> {
.class nested public Innermost<T, U, V> {
}
}
}
Puede usar el Ildasm.exe (Desensamblador de IL) para examinar las clases anidadas definidas en los lenguajes de alto nivel y observar este esquema de nomenclatura.