Home > Articles > Programming > Windows Programming

  • Print
  • + Share This
From the author of

Emitting Dynamic Assemblies

There are four major tools for emitting assemblies containing MSIL. Each of these tools can be found in the System.Reflection or System.Reflection.Emit namespace:

  • Info classes: MethodInfo, FieldInfo, EventInfo, ConstructorInfo, and others. These classes are used to represent elements such as types, constructors, and methods.

  • Builder classes such as AssemblyBuilder, TypeBuilder, and MethodBuilder. These classes are used to emit specific kinds of entities.

  • The ILGenerator, which is retrieved contextually. For example, if you want to generate a property, you can request an ILGenerator from a PropertyBuilder. A PropertyBuilder's ILGenerator is used to generate the MSIL for that property.

  • OpCodes, which equate to a single line or a just a couple of lines of MSIL code.

Collectively, these four ingredients are analogous to entities that you have to create or code manually in Visual Studio .NET to yield an assembly, and are the ingredients necessary to emit a dynamic assembly—that is, to create code without interacting with Visual Studio .NET.

The basic steps for emitting a dynamic assembly are analogous to creating a solution and project and compiling an assembly. These are roughly as follows:

  1. Create an assembly with an AssemblyBuilder. This is analogous to creating a new project.

  2. Create a module with a ModuleBuilder. This is analogous to adding a module to a project.

  3. Create a type with a TypeBuilder. This is analogous to adding a class, structure, or enumeration to a module.

  4. Create members in your type with the various builders for the various types. This is analogous to coding members in your type. The ConstructorBuilder, CustomAttributeBuilder, EventBuilder, FieldBuilder, LocalBuilder, MethodBuilder, and PropertyBuilder are available for this purpose.

  5. Finally, use ParameterBuilders, ILGenerators, OpCodes, and token structures for adding method parameters and generating the equivalent of individual lines of code.

From the steps above, I hope it's apparent that a lot of the grunt work is managed for you by builders and other entities in the System.Reflection.Emit namespace. I don't want to suggest that writing emitters is easy, though. It's important to remember that when you're creating an emitter you're writing code that will be writing code decomposed to micro-steps.

There are three reasons I can think of to write an emitter:

  • To avoid having to write dozens or hundreds of times the code that one emitter can write instead

  • To write software that adapts or grows in capability over time

  • For the pure joy of it

For example, if one emitter can keep you from writing the code to implement a common pattern a hundred times, then write an emitter that generates the assembly. Writing adaptive software will probably not be an easy endeavor. (And of course fun needs no explanation.)

  • + Share This
  • 🔖 Save To Your Account