Definizione di un tipo tramite reflection emit
I tipi vengono definiti nell'ambito di un modulo dinamico tramite il metodo ModuleBuilder.DefineType. DefineType restituisce un TypeBuilder. In questo argomento il nome del tipo viene sempre fornito in forma completa, incluso lo spazio dei nomi. Se ad esempio il nome del tipo è Aaa.Bbb.Ccc, Aaa.Bbb verrà considerato essere lo spazio dei nomi.
Sono disponibili le seguenti opzioni per la definizione dei tipi tramite la reflection emit:
Definizione di una classe o interfaccia con il nome specificato.
Definizione di una classe o interfaccia con il nome e gli attributi specificati.
Definizione di una classe con il nome, gli attributi e la classe base specificati.
Definizione di una classe con il nome, gli attributi, la classe base e l'insieme di interfacce implementato dalla classe specificati.
Definizione di una classe con il nome, gli attributi, la classe base e le dimensioni di compressione specificati.
Definizione di una classe con il nome, gli attributi, la classe base e le dimensioni complessive di classe specificati.
Definizione di una classe con il nome, gli attributi, la classe base, le dimensioni di compressione e le dimensioni complessive di classe specificati.
Per poter utilizzare un tipo è necessario chiamare il metodo TypeBuilder.CreateType. CreateType consente di completare la creazione del tipo. Dopo la chiamata di CreateType, il chiamante sarà in grado di creare istanze del tipo (mediante il metodo Activator.CreateInstance) e richiamare membri del tipo (mediante il metodo Type.InvokeMember). È un errore richiamare metodi che modificano l'implementazione di un tipo dopo aver chiamato CreateType. Se ad esempio il chiamante tenta di aggiungere nuovi membri a un tipo in Common Language Runtime verrà generata un'eccezione.
Per creare un inizializzatore di classe è necessario utilizzare il metodo TypeBuilder.DefineTypeInitializer. DefineTypeInitializer restituisce un ConstructorBuilder.
Per definire tipi annidati è necessario utilizzare uno dei metodi TypeBuilder.DefineNestedType.
Il metodo TypeBuilder.AddDeclarativeSecurity aggiunge la sicurezza dichiarativa a un tipo compilato. È possibile chiamare più volte AddDeclarativeSecurity specificando a ogni chiamata un'azione di sicurezza (quale Demand, Assert, Deny) e un set di autorizzazioni a cui si applica l'azione.
Attributi
È possibile specificare le interfacce mediante gli attributi TypeAttributes.Interface e TypeAttributes.Abstract.
È possibile specificare classi concrete, ovvero non estensibili, mediante l'attributo TypeAttributes.Sealed.
La visibilità del tipo è determinata da vari attributi. Vedere la descrizione dell'enumerazione TypeAttributes.
Se è specificato TypeAttributes.LayoutSequential, il caricatore di classe disporrà i campi nell'ordine in cui vengono letti dai metadati. Il caricatore di classe considera le dimensioni di compressione indicate ma ignora eventuali offset di campo specificati. I metadati conservano l'ordine di creazione delle definizioni di campo, non modificano tale ordine nemmeno in occasione di un'operazione di unione. Il caricatore rispetterà l'offset di campo indicato solo se è specificato TypeAttributes.ExplicitLayout.
Problemi noti
Durante la reflection emit non viene verificato se una classe non astratta che implementa un'interfaccia ha implementato tutti i metodi dichiarati nell'interfaccia. Se tuttavia la classe non implementa tutti i metodi dichiarati in un'interfaccia, tale classe non verrà caricata dal runtime.
Sebbene TypeBuilder derivi da Type, alcuni dei metodi astratti definiti nella classe Type non sono implementati completamente in TypeBuilder. Questi metodi TypeBuilder generano l'eccezione NotSupportedException. È possibile ottenere le funzionalità desiderate recuperando il tipo creato mediante Type.GetType o Assembly.GetType e operando una reflection su tale tipo.