There are several ways to use reflection in .NET. Reflection can be used for runtime-type inspection and late-bound object creation using the types in the System.Reflection namespace. Reflection can also be used for dynamic code creation, which is supported by the types in this namespace, System.Reflection.Emit. Dynamic code creation means a programmer can programmatically create code constructs such as methods and events from within code, using the appropriate corresponding type (for example, MethodBuilder and EventBuilder). These code elements are all ingredients that can be added to a dynamic assembly, represented by an AssemblyBuilder object. Dynamic assemblies can be saved to disk as PE (Portable Executable) files, typically in DLL form. Or, alternatively, emit it directly to memory for immediate use, at the expense of persistence (memory-only types disappear when the containing AppDomain terminates).
The ILGenerator class allows you to emit the MSIL (Microsoft Intermediate Language) for your code, using the corresponding GetILGenerator( ) method from a builder class. This process (sometimes known as "baking") allows you to convert the information in the builder object into a legitimate .NET type. You can then instantiate this newly created type on the spot.
The primary use of the System.Reflection.Emit namespace is to create compilers and script hosts, although many other uses are possible, including programs that dynamically create code that is fine-tuned to process a specific regular expression (see System.Text.RegularExpressions.Regex.CompileToAssembly( )). When creating dynamic types, you generally begin by creating an AssemblyBuilder, which contains one or more ModuleBuilder objects. This in turn contains TypeBuilder instances. TypeBuilder objects contain most of the other ingredients in this namespace, including classes for building events, properties, methods, and enumerations.
Many of the builder classes in this namespace use similar methods and properties for retrieving information about the containing module (for example, ConstructorBuilder.GetModule( )), getting an internal handle to the metadata (for example, EnumBuilder.TypeHandle( )), and retrieving attributes (MethodBuilder.Attributes). Also note that though the builder classes derive from the corresponding "-Info" class (for example, MethodBuilder derives from System.Reflection.MethodInfo), not all of the inherited properties are currently supported. This includes methods such as Invoke( ). To use these methods, you may need to reflect on the object with System.Type.GetType( ). Figure 36-1 shows the types in this namespace.