Definieren eines Typs mittels Reflektionsausgabe
Typen werden im Rahmen dynamischer Module mithilfe der ModuleBuilder.DefineType-Methode definiert. DefineType gibt TypeBuilder zurück. Im vorliegenden Thema besteht der Typname immer aus einem vollen Pfadnamen, der den Namespace einschließt. Wenn z. B. der Typname "Aaa.Bbb.Ccc" lautet, wird "Aaa.Bbb" als Namespace angenommen.
Die Reflektionsausgabe stellt folgende Optionen zur Definition von Typen zur Verfügung:
Definieren einer Klasse oder Schnittstelle mit dem angegebenen Namen.
Definieren einer Klasse oder Schnittstelle mit dem angegebenen Namen und Attributen.
Definieren einer Klasse mit dem angegebenen Namen, Attributen und der Basisklasse.
Definieren einer Klasse mit dem angegebenen Namen, Attributen, der Basisklasse und dem Satz an Schnittstellen, den die Klasse implementiert.
Definieren einer Klasse mit dem angegebenen Namen, Attributen, der Basisklasse und der Komprimierungsgröße.
Definieren einer Klasse mit dem angegebenen Namen, Attributen, der Basisklasse und der gesamten Klassengröße.
Definieren einer Klasse mit dem angegebenen Namen, Attributen, der Basisklasse, der Komprimierungsgröße und der gesamten Klassengröße.
Bevor ein Typ verwendet werden kann, muss die TypeBuilder.CreateType-Methode aufgerufen werden. CreateType schließt die Erstellung eines Typs ab. Nach dem Aufruf von CreateType kann der Aufrufer (mithilfe der Activator.CreateInstance-Methode) den Typ instanziieren und (mithilfe der Type.InvokeMember-Methode) Member des Typs aufrufen. Es ist nicht zulässig, Methoden zur Änderung einer Typimplementierung aufzurufen, nachdem CreateType aufgerufen wurde. Beispielsweise wird durch die Common Language Runtime eine Ausnahme ausgelöst, wenn der Aufrufer versucht, einem Typ neue Elemente hinzuzufügen.
Ein Klasseninitialisierer wird mithilfe der TypeBuilder.DefineTypeInitializer-Methode erstellt. DefineTypeInitializer gibt ConstructorBuilder zurück.
Geschachtelte Typen werden mithilfe einer der TypeBuilder.DefineNestedType-Methoden definiert.
Durch die TypeBuilder.AddDeclarativeSecurity-Methode wird einem erstellten Typ deklarative Sicherheit hinzugefügt. AddDeclarativeSecurity kann mehrmals aufgerufen werden, wobei jeder Aufruf eine Sicherheitsaktion (z. B. Demand, Assert oder Deny) und eine Gruppe von Berechtigungen angibt, die die Aktion betreffen.
Attribute
Schnittstellen werden mithilfe des TypeAttributes.Interface-Attributs und des TypeAttributes.Abstract-Attributs angegeben.
Konkrete Klassen (die nicht erweitert werden können) werden mithilfe des TypeAttributes.Sealed-Attributs angegeben.
Verschiedene Attribute legen die Typsichtbarkeit fest. Siehe dazu die Beschreibung der TypeAttributes-Enumeration.
Wenn TypeAttributes.LayoutSequential angegeben ist, legt das Ladeprogramm für Klassen Felder in der Reihenfolge an, in der sie aus den Metadaten gelesen werden. Das Ladeprogramm für Klassen berücksichtigt die angegebene Komprimierungsgröße, ignoriert jedoch die angegebenen Feldoffsets. Die Metadaten halten die Reihenfolge ein, in der die Felddefinitionen ausgegeben werden. Selbst bei einem Mergevorgang wird die Reihenfolge der Felddefinitionen durch die Metadaten nicht verändert. Das Ladeprogramm berücksichtigt die angegebenen Feldoffsets nur dann, wenn das TypeAttributes.ExplicitLayout angegeben ist.
Bekannte Probleme
Die Reflektionsausgabe überprüft nicht, ob eine nicht abstrakte Klasse, die eine Schnittstelle implementiert, alle in der Schnittstelle deklarierten Methoden implementiert hat. Wenn die Klasse jedoch nicht alle in einer Schnittstelle deklarierten Methoden implementiert, wird sie von der Common Language Runtime nicht geladen.
Obwohl TypeBuilder von Type abgeleitet ist, sind einige der in der Type-Klasse definierten abstrakten Methoden nicht vollständig in TypeBuilder implementiert. Diese TypeBuilder-Methoden lösen die NotSupportedException aus. Die gewünschte Funktionalität kann durch Abrufen des erstellten Typs mithilfe von Type.GetType bzw. Assembly.GetType und durch Reflektieren des abgerufenen Typs erzielt werden.