CHAPTER 18 UNDERSTANDING CIL AND THE ROLE OF DYNAMIC ASSEMBLIES
UsingNamespace()
Specifies the namespace to be used in evaluating locals and watches for
the current active lexical scope
The key method of ILGenerator is Emit(), which works in conjunction with the
System.Reflection.Emit.OpCodes class type. As mentioned earlier in this chapter, this type exposes a
good number of read-only fields that map to raw CIL opcodes. The full set of these members are all
documented within online help, and you will see various examples in the pages that follow.
Emitting a Dynamic Assembly
To illustrate the process of defining a .NET assembly at runtime, let’s walk through the process of
creating a single-file dynamic assembly named MyAssembly.dll. Within this module is a class named
HelloWorld. The HelloWorld class supports a default constructor and a custom constructor that is used to
assign the value of a private member variable (theMessage) of type string. In addition, HelloWorld
supports a public instance method named SayHello(), which prints a greeting to the standard I/O
stream, and another instance method named GetMsg(), which returns the internal private string. In
effect, you are going to programmatically generate the following class type:
// This class will be created at runtime
// using System.Reflection.Emit.
public class HelloWorld
{
private string theMessage;
HelloWorld() {}
HelloWorld(string s) {theMessage = s;}
}
public string GetMsg() {return theMessage;}
public void SayHello()
{
System.Console.WriteLine("Hello from the HelloWorld class!");
}
Assume you have created a new Visual Studio Console Application project workspace named
DynamicAsmBuilder and import the System.Reflection, System.Reflection.Emit, and System.Threading
namespaces. Define a static method named CreateMyAsm(). This single method is in charge of the
following:
•
Defining the characteristics of the dynamic assembly (name, version, etc.)
•
Implementing the HelloClass type
•
Saving the in-memory assembly to a physical file
Also note that the CreateMyAsm() method takes as a single parameter a System.AppDomain type,
which will be used to obtain access to the AssemblyBuilder type associated with the current application
domain (see Chapter 17 for a discussion of .NET application domains). Here is the complete code, with
analysis to follow:
// The caller sends in an AppDomain type.
public static void CreateMyAsm(AppDomain curAppDomain)
{
686