Meta-Programming

The ability to dynamically create new types at runtime is known as meta-programming. The CLR provides this capability through Reflection.Emit. Creating dynamic types is a fundamental facility in the remoting services. For example, COM and CORBA can produce code for proxy objects at IDL compile time. This code is then linked with the client and server programs. With the CLR's remoting services, the runtime environment dynamically creates proxy objects whenever the need arises. This approach eliminates the problem of locating and loading the DLL that contains the proxy code at runtime.

Figure 3.7 shows some of the classes involved in providing meta-programming facilities. The diagram is similar to Figure 3.1, which depicts the reflection class hierarchy. The Builder classes provide the functionality needed to create a new type or member at runtime.

Figure 3.7. Meta-programming classes


Listing 3.9 demonstrates how to dynamically create a new type and then persist it to disk. It loads the assembly from disk, creates an instance of the new type, and calls a method on the new type. As types are located in modules and modules are located within assemblies, it follows that the creation of a new type requires the creation of a module and an assembly.

Listing 3.9. Using meta-programming
using System.Reflection.Emit;
using System.Threading;

public class DynamicType
{
  private static void CreateMethodBody(MethodBuilder m)
  {
    ILGenerator il = m.GetILGenerator();
    il.EmitWriteLine("Hello World! from a new type");
    il.Emit(OpCodes.Ret);
  }
  public static int Main(String[] args)
  {
    AssemblyName an = new AssemblyName();
    an.Name = "MyAssembly";
    AssemblyBuilder ab =
            Thread.GetDomain().DefineDynamicAssembly(an,
                       AssemblyBuilderAccess.RunAndSave);
    ModuleBuilder mb = ab.DefineDynamicModule("MyModule",
                                 "MyAssembly.dll", true);
    TypeBuilder tb = mb.DefineType ("Sample.NewType",
                                   TypeAttributes.Public);
    MethodBuilder m = tb.DefineMethod("MyMethod",
                                 MethodAttributes.Public,
                                 null, null);
    CreateMethodBody(m);
    tb.CreateType();
    ab.Save("MyAssembly.dll");
    Type t = Type.GetType("Sample.NewType,MyAssembly",
                          true);
    Object o = Activator.CreateInstance(t);
    MethodInfo myMethod = t.GetMethod("MyMethod");
    myMethod.Invoke(o,null);
    myMethod = t.GetMethod("ToString");
    Console.WriteLine(myMethod.Invoke(o,null));
    return 0;
  }
}

Listing 3.9 produces the following output:

Hello World! from a new type 
Sample.NewType

Of course, running this program creates an assembly in the current directory. You can use ILDASM to display its contents, just to show it is a valid CLR file (see Figure 3.8).

Figure 3.8. Output of Listing 3.9: an assembly in the current directory


Also using ILDASM, you can show the emitted IL for MyMethod (see Figure 3.9).

Figure 3.9. IL for MyMethod


Meta-programming is somewhat beyond the scope of this book, so it will not be covered in detail here. This short introduction should whet your appetite to learn more, however.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset