This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!
Defining a Type
Types are defined in the scope of a dynamic module using the ModuleBuilder.DefineType methods. DefineType returns a TypeBuilder object. In what follows, the type name is always a full path name. The Reflection Emit APIs provide 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 superclass.
- Define a class with the given name, attributes, superclass, and the set of interfaces that the class implements.
- Define a class with the given name, attributes, superclass, and packing size.
- Define a class with the given name, attributes, superclass, and the class size as a whole.
- Define a class with the given name, attributes, superclass, 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 Type.CreateInstance) and invoke members of the type (using Type.InvokeMember). It is an error to invoke methods that change the implementation of a type after CreateType has been called. For example, the runtime will throw an exception if the caller tries to add new members to a type.
A class initializer is created using the method TypeBuilder.DefineTypeInitializer. DefineTypeInitializer returns a ConstructorBuilder object.
Nested types are defined using one of TypeBuilder.DefineNestedType methods.
The TypeBuilder.AddDeclarativeSecurity method adds declarative security to a type being built. AddDeclarativeSecurity may be called several times with each call specifying a security action (e.g., Demand, Assert, Deny) and a set of permissions that the action applies to.
Attributes
- Interfaces are specified using the TypeAttributes.Interface and TypeAttributes.Abstract attributes.
- Value types are specified using the TypeAttributes.ValueType attribute.
- Concrete classes, i.e., classes that may not be extended are specified using the TypeAttributes.Sealed attribute.
- There are several attributes that determine type visibility. See the description of the TypeAttributes enum.
- If the TypeAttributes.LayoutSequential is specified, the class loader lays out fields in the order that it reads them from metadata. The class loader takes into account the packing size specified 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.
Known Issues
- Reflection.Emit does not verify if 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 execution engine will fail to load the class.
- Although TypeBuilder is a subclass of 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. Two examples of methods that are not fully implemented are TypeBuilder.CreateInstance and TypeBuilder.InvokeMember.