Definir un tipo con la emisión de la reflexión
Actualización: noviembre 2007
En el ámbito de un módulo dinámico, los tipos se definen con el método ModuleBuilder.DefineType. DefineType devuelve un objeto TypeBuilder. En este tema, el nombre del tipo es siempre un nombre de ruta de acceso completo que incluye el espacio de nombres. Por ejemplo, si el nombre del tipo es Aaa.Bbb.Ccc, se asume que Aaa.Bbb es el espacio de nombres.
La emisión de la reflexión proporciona las siguientes opciones para definir tipos:
Definir una clase o una interfaz con el nombre dado.
Definir una clase o una interfaz con el nombre y los atributos dados.
Definir una clase con el nombre, los atributos y la clase base dados.
Definir una clase con el nombre, los atributos y la clase base dados, y el conjunto de interfaces que implementa la clase.
Definir una clase con el nombre, los atributos, la clase base y el tamaño de empaquetado dados.
Definir una clase con el nombre, los atributos y la clase base dados, y el tamaño de clase como conjunto.
Definir una clase con el nombre, los atributos, la clase base, el tamaño de empaquetamiento dados, y el tamaño de clase como conjunto.
Antes de utilizar un tipo, debe llamarse al método TypeBuilder.CreateType. CreateType completa la creación del tipo. Después de la llamada a CreateType, el llamador puede crear una instancia del tipo (con el método Activator.CreateInstance) e invocar a los miembros del tipo (con el método Type.InvokeMember). Es un error invocar métodos que cambian la implementación de un tipo después de haber llamado a CreateType. Por ejemplo, Common Language Runtime produce una excepción si el llamador intenta agregar nuevos miembros a un tipo.
Un inicializador de clase se crea con el método TypeBuilder.DefineTypeInitializer. DefineTypeInitializer devuelve un objeto ConstructorBuilder.
Los tipos anidados se definen mediante uno de los métodos TypeBuilder.DefineNestedType.
El método TypeBuilder.AddDeclarativeSecurity agrega seguridad declarativa a un tipo que se está creando. Se puede llamar varias veces a AddDeclarativeSecurity, especificando en cada llamada una acción de seguridad (como Demand, Assert, Deny) y un conjunto de permisos a los que se aplica la acción.
Atributos
Las interfaces se especifican mediante los atributos TypeAttributes.Interface y TypeAttributes.Abstract.
Las clases concretas (clases que no se pueden extender) se especifican mediante el atributo TypeAttributes.Sealed.
Varios atributos determinan la visibilidad del tipo. Vea la descripción de la enumeración TypeAttributes.
Si se especifica TypeAttributes.LayoutSequential, el cargador de clases dispone los campos en el orden en que se leen desde los metadatos. El cargador de clases tiene en cuenta el tamaño de empaquetado especificado, pero pasa por alto los desplazamientos de campo que se hayan establecido. Los metadatos conservan el orden en que se emiten las definiciones de los campos. Incluso después de una combinación, los metadatos no reordenan las definiciones de los campos. El cargador admitirá los desplazamientos de campo establecidos sólo si se especifica TypeAttributes.ExplicitLayout.
Problemas conocidos
La emisión de la reflexión no comprueba si una clase no abstracta que implementa una interfaz ha implementado todos los métodos declarados en la interfaz. Sin embargo, si la clase no implementa todos los métodos declarados en una interfaz, el motor en tiempo de ejecución no carga la clase.
Aunque TypeBuilder se deriva de Type, algunos de los métodos abstractos definidos en la clase Type no están del todo implementados en TypeBuilder. Estos métodos TypeBuilder producen la excepción NotSupportedException. Para obtener la funcionalidad deseada, se puede recuperar el tipo creado mediante Type.GetType o Assembly.GetType y después reflejarlo en el tipo recuperado.