|Important||This document may not represent best practices for current development, links to downloads and other resources may no longer be valid. Current recommended version can be found here.|
Defining a Type with Reflection Emit
Types are defined in the scope of a dynamic module using the ModuleBuilder.DefineType method. DefineType returns a TypeBuilder. In this topic, the type name is always a full path name that includes the namespace. For example, if the type name is Aaa.Bbb.Ccc, Aaa.Bbb is assumed to be the namespace.
Reflection emit provides the following options for defining types:
Define a class or interface with the given name.
Define a class or interface with the given name and attributes.
Define a class with the given name, attributes, and base class.
Define a class with the given name, attributes, base class, and the set of interfaces that the class implements.
Define a class with the given name, attributes, base class, and packing size.
Define a class with the given name, attributes, base class, and the class size as a whole.
Define a class with the given name, attributes, base class, packing size, and the class size as a whole.
Before a type is used, the TypeBuilder.CreateType method must be called. CreateType completes the creation of the type. Following the call to CreateType, the caller can instantiate the type (using the Activator.CreateInstance method) and invoke members of the type (using the Type.InvokeMember method). It is an error to invoke methods that change the implementation of a type after CreateType has been called. For example, the common language runtime throws an exception if the caller tries to add new members to a type.
Nested types are defined using one of the TypeBuilder.DefineNestedType methods.
The TypeBuilder.AddDeclarativeSecurity method adds declarative security to a type being built. AddDeclarativeSecurity can be called several times with each call specifying a security action (such as Demand, Assert, Deny) and a set of permissions that the action applies to.
Interfaces are specified using the TypeAttributes.Interface and TypeAttributes.Abstract attributes.
Concrete classes (classes that cannot be extended) are specified using the TypeAttributes.Sealed attribute.
Several attributes determine type visibility. See the description of the TypeAttributes enumeration.
If TypeAttributes.LayoutSequential is specified, the class loader lays out fields in the order they are read from metadata. The class loader considers the specified packing size but ignores any specified field offsets. The metadata preserves the order in which the field definitions are emitted. Even across a merge, the metadata will not reorder the field definitions. The loader will honor the specified field offsets only if TypeAttributes.ExplicitLayout is specified.
Reflection emit does not verify whether a non-abstract class that implements an interface has implemented all the methods declared in the interface. However, if the class does not implement all the methods declared in an interface, the runtime does not load the class.
Although TypeBuilder is derived from Type, some of the abstract methods defined in the Type class are not fully implemented in TypeBuilder. These TypeBuilder methods throw the NotSupportedException. The desired functionality can be obtained by retrieving the created type using Type.GetType or Assembly.GetType and reflecting on the retrieved type.