Runtime code generation for types

Last week I discussed how you could use runtime code generation to create fast methods to replace slow reflection code, even when you didn’t have the target types to compile against. But runtime code generation allows you to go further than isolated methods: you can actually create whole new types at runtime.

Why might you want to do that? The classic example is to subclass a user-defined class so as to intercept certain calls that you are interested in. Some object-relational mappers do this, for example, so that users can write entity properties using automatic property syntax and yet the object-relational mapper can still intercept the getters and setters to perform, for example, lazy loading. Another example could be to create objects that are implemented according to a regular pattern but whose properties are determined from a schema that is only available at runtime (say, from a configuration file or a database’s catalogue); such objects might not be terribly useful for programming with, unless there were design-time interfaces through which you could address them, but could be handy for using with ASP.NET Dynamic Data or a data grid control.

Of the methods I talked about in my previous post, expression trees can’t be used to implement whole types. They’re restricted to, well, expressions. CodeDom can be used, in the same way and with the same considerations as before, so I’m not going to repeat that discussion. Dynamic methods can’t be used, because like expression trees they represent methods rather than types — but there is a closely related technique which can.

Enter the Reflection.Emit namespace

As well as the DynamicMethod class, the Reflection.Emit namespace includes builder classes for all the elements that make up a .NET assembly: modules, types, fields, properties, methods and so on. In many cases, the builder class is actually just like the familiar Reflection equivalent — for example, PropertyBuilder is a derived class of PropertyInfo — but writeable instead of read-only. For generating code, the MethodBuilder class exposes an ILGenerator which is the same as that exposed by DynamicMethod. So creating a type with these builder classes is a bit like combining what you already know about read-only Reflection with what you already know about dynamic method code generation. Easy, right?

Well, there are a few small hoops that you need to jump through. But once you’ve got your head around them… yes, it’s not too difficult. Let’s try it!

Preliminaries

The first thing we need to do is get some preliminaries out of the way. A type has to live inside an assembly. But it’s not quite that simple. Back in the day, some bright spark at Microsoft decided it would be a good idea to distinguish between modules (roughly, physical files that contain stuff) and assemblies (roughly, units of deployment and versioning). The idea was that your assembly, instead of being a huge monolithic DLL or EXE, could be split up so that large resources could be… actually, I don’t know why I’m explaining this, as only seven people even remember that the whole ‘multi-module assembly’ concept ever existed, and they are one by one being erased from history by a mysterious and terrifying force with a dodgy Austrian accent. All you need to know is that your ‘assembly’ is actually a wrapper around a thing called a ‘module,’ and it is within this mysterious ‘module’ that all the excitement happens.

So without further ado, let’s create a dynamic assembly-module-thingy to hold our runtime generated types.

AssemblyName name = new AssemblyName("MyRuntimeTypes");
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
ModuleBuilder module = assembly.DefineDynamicModule("MyRuntimeTypes");

Not much to see here, except for the AssemblyBuilderAccess option. For most dynamic assemblies, you’ll set this to Run. However, if you want to be able to persist the emitted assembly, you can specify RunAndSave instead. (In this case, you’ll need to call the DefineDynamicModule overload which also takes a file name.) You might do this to cache the dynamic assembly to save rebuilding it on every run, or for diagnostic purposes so you can open it in Reflector or ILDASM and see where it all went so horribly wrong.

Great, so now we have a big empty module. Time to get down to business.

Defining a dynamic type

To define a dynamic type in a module, you call the DefineType method. (Gasps of amazement.) This gives you a TypeBuilder object, which you can then party on. Once you’ve got the type the way you want it, you call CreateType and this gives you a Type object representing the compiled type — you can now create instances of this using Activator.CreateInstance or the faster techniques I discussed in the previous post.

For my example, I’m going to imagine that my system includes a user profile object whose properties are defined in a configuration file or something, and I have to implement an object with these properties so it can be displayed in a dynamic form builder or a data grid or something like that. (It’s not a stupendously realistic example but I want to keep it reasonably simple so as not to get bogged down in extraneous detail.) So here’s how I define and build that type:

TypeBuilder type = module.DefineType("Mindscape.RuntimeTypes.Profile");
// magic goes here
Type compiledType = type.CreateType();

What about inheritance? You can pass a parent type to DefineType:

TypeBuilder type = module.DefineType("Mindscape.RuntimeTypes.Profile", TypeAttributes.Public, typeof(ProfileBase));

If you want your dynamic type to implement an interface, you can specify it using AddInterfaceImplementation:

type.AddInterfaceImplementation(typeof(IProfile));

Of course this doesn’t create the actual properties or methods to implement the interface — it just marks the type as implementing the interface. You’ll still need to supply the interface members, or you’ll get an error when you create the type.

Implementing the type’s members: fields

Implementing a member field is dead easy: call the DefineField method:

FieldBuilder myField = type.DefineField("_myField", typeof(int), FieldAttributes.Private);

You’re probably going to want to refer to your fields when you come to build your methods and properties (otherwise, there’s not much point having the fields, right?), so you’ll usually want to keep references to them.

Implementing the type’s members: methods

Defining a method is dead easy too: call the (you guessed it) DefineMethod method.

MethodBuilder myMethod = type.DefineMethod("GetLength", MethodAttributes.Public, typeof(int), new Type[] { typeof(string) });

Here the third argument is the return type of the method, and the fourth the parameter types: so the above is equivalent to the signature public int GetLength(string).

Of course if you try to create the type in this state you will get an error because you haven’t provided a method body for GetLength. Fortunately, you can do this in exactly the same way as you did for ‘floating’ dynamic methods, as discussed in my earlier post.

ILGenerator ilgen = myMethod.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Callvirt, typeof(string).GetProperty("Length").GetGetMethod());
ilgen.Emit(OpCodes.Ret);

As always with IL generation the tricky bit is knowing what IL to write and as always the answer is to cheat. Write an example of the type and its methods in C#, compile it (in Release mode), open the compiled assembly in ILDASM and copy the IL opcodes from there (mutatis mutandis of course). It’s not as hard as it looks! However, there are some special things to be aware of when your method needs to refer to other members of the type you’re building. We’ll talk about those in a moment.

Implementing the type’s properties

After all that alarming IL, properties are nice and easy. The only thing to watch out for is that you need to implement the get and set code (if you have any of course) as methods, conventionally called get_Xxx and set_Xxx (where Xxx is your property name). The signatures of the getter and setter must be consistent with the property type. With this done, you just associate those methods with the property using SetGetMethod and/or SetSetMethod. Unlike the C# syntactic sugar, you don’t write any code in the property itself.

PropertyBuilder myProperty = type.DefineProperty("MyProperty", PropertyAttributes.None, typeof(int), Type.EmptyTypes);
 
MethodBuilder myPropertyGetter = type.DefineMethod("get_MyProperty", MethodAttributes.Public, typeof(int), Type.EmptyTypes);  // getter takes no args and returns the property type
// implement myPropertyGetter using ILGenerator in the usual way
 
myProperty.SetGetMethod(myPropertyGetter);

Notice that the property itself doesn’t even have an access modifier like public or protected — the access modifiers are on the getter and setter, again slightly different from the way C# lays it out.

And there’s more

TypeBuilder also provides methods for defining events, constructors, generic type parameters etc., setting attributes on members, creating nested types and all the other spiffy things you can do to make your CLR types a joy to behold. I’m not going to plough through them all — you can figure them out if you need them.

Putting it all together

We’ve seen how to define members in isolation. Now let’s put it together and see how to build an entire type.

For our example, I just want to create a set of read-write properties according to some input spec (maybe read in from a config file), but I want the class to raise property changed notifications so it can be used in WPF or Silverlight.

This leaves me with a design decision: should I implement INotifyPropertyChanged in the runtime generated code, or should I create a base class which implements INotifyPropertyChanged and have my runtime generated class take advantage of that? From the point of view of a consumer of the runtime generated class, there’s not much difference between these two options, but from the point of view of implementation, the second is a lot easier, both to understand and to maintain, because I can write the INotifyPropertyChanged implementation, which is unchanging, in C# which everybody understands, and use IL only for the dynamic bits.

So enter a base class:

public class ViewModelBase : INotifyPropertyChanged
{
  protected void Set<T>(ref T field, T value, string propertyName)
  {
    if (!Object.Equals(field, value))
    {
      field = value;
      OnPropertyChanged(propertyName);
    }
  }
 
  protected virtual void OnPropertyChanged(string propertyName)
  {
    var handler = PropertyChanged;
    if (handler != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }
 
  public event PropertyChangedEventHandler PropertyChanged;
}

You’re cordially invited to ILDASM the ViewModelBase class and imagine the joy of generating the equivalent code dynamically into the Profile class.

With that helper sorted, we can set to implementing the Profile class itself:

private static Type CreateProfileType(Dictionary<string, Type> properties)
{
  AssemblyName name = new AssemblyName("MyRuntimeTypes");
  AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
  ModuleBuilder module = assembly.DefineDynamicModule("MyRuntimeTypes");
 
  // Our runtime-generated type inherits from ViewModelBase
  TypeBuilder type = module.DefineType("Mindscape.RuntimeTypes.Profile", TypeAttributes.Public, typeof(ViewModelBase));
 
  foreach (var property in properties)
  {
    ImplementProperty(type, property.Key, property.Value);
  }
 
  return type.CreateType();
}

This is all familiar framework, but this time, we’re implementing a property for every entry in the dictionary, instead of just some hardwired name. The real work happens in the ImplementProperty method:

private static void ImplementProperty(TypeBuilder type, string propertyName, Type propertyType)
{
  FieldBuilder field = type.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
 
  PropertyBuilder property = type.DefineProperty(propertyName, PropertyAttributes.None, propertyType, Type.EmptyTypes);
 
  MethodBuilder getter = type.DefineMethod("get_" + propertyName, MethodAttributes.Public, propertyType, Type.EmptyTypes);
  ILGenerator getterIL = getter.GetILGenerator();
  getterIL.Emit(OpCodes.Ldarg_0);
  getterIL.Emit(OpCodes.Ldfld, field);
  getterIL.Emit(OpCodes.Ret);
 
  MethodBuilder setter = type.DefineMethod("set_" + propertyName, MethodAttributes.Public, typeof(void), new Type[] { propertyType });
  ILGenerator setterIL = setter.GetILGenerator();
  setterIL.Emit(OpCodes.Ldarg_0);
  setterIL.Emit(OpCodes.Ldarg_0);
  setterIL.Emit(OpCodes.Ldflda, field);
  setterIL.Emit(OpCodes.Ldarg_1);
  setterIL.Emit(OpCodes.Ldstr, propertyName);
  setterIL.Emit(OpCodes.Call, typeof(ViewModelBase).GetMethod("Set", BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(propertyType));
  setterIL.Emit(OpCodes.Ret);
 
  property.SetGetMethod(getter);
  property.SetSetMethod(setter);
}

Whew! Although all that IL looks a bit scary, we can pick this apart bit by bit to see how each property gets implemented. First we need a backing field, so we call DefineField. We’re going to need to refer to this field later, when we implement the property getter and setter, so we keep hold of the returned FieldBuilder. Next we define the property itself, which is as exciting as a not very exciting thing. Then comes the good bit: defining the property getter and setter. Notice the “get_”/”set_” prefix convention and the getter and setter signatures.

The setter has a couple of interesting features. The first is that when we call the base class Set method in the setter, we can pass a MethodInfo obtained in the usual way, via good old-fashioned Reflection. The second is that when we want to refer to the backing field — to get its value in the getter, and to pass a reference to it in the setter — we can do so using the FieldBuilder we got back from DefineField. This might seem inconsistent — how come we use an old-school Reflection MethodInfo for the method but a dynamic FieldBuilder for the field? Well, all the ‘builder’ classes are also ‘info’ classes: for example, a FieldBuilder is a FieldInfo. The Emit method accepts the ‘info’ classes, so that we can pass members that aren’t part of the dynamic assembly (like the ViewModelBase.Set method), and thanks to inheritance this also allows the Emit method to accept the ‘builder’ classes, which we need so we can pass members which *are* part of the dynamic assembly (like the field).

Finally, how did I know what IL to write in the getter and setter? You should know this by now: I cheated. I wrote an example Profile class in C#, compiled that, opened it in ILDASM and just adapted the method bodies to the property name and type variables.

It works!

And that’s it. We now have a working type — we can instantiate it from a list of properties, set those dynamically created properties, see the change notifications and retrieve their values.

var t = CreateProfileType(new Dictionary<string, Type> { { "SomeInt", typeof(int) }, { "SomeStr", typeof(string) } });
dynamic o = Activator.CreateInstance(t);
((INotifyPropertyChanged)o).PropertyChanged += (s, e) => { Console.WriteLine("changed " + e.PropertyName); };
o.SomeInt = 123;
o.SomeStr = "hello";
Console.WriteLine(o.SomeInt);
Console.WriteLine(o.SomeStr);

As I said, it’s not a very realistic example, but I hope it’s simple enough to be easy to follow, and that this has given you enough of a leg up to create your own more sophisticated runtime generated types when the occasion demands! Have fun!

P.S. Carel Lotz was kind enough to draw our attention to a library named RunSharp which provides a rather friendlier wrapper over some of the IL nastiness. He’s got a tutorial on it at http://fromthedevtrenches.blogspot.com/2010/08/runsharp-il-generation-for-dummies.html — check it out!

Tagged as Visual Studio

2 Responses to “Runtime code generation for types”

  • Creating classes at runtime in .NET…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  • […] Runtime code generation for types – Ivan Towlson continues his exploration of runtime code generation looking this time at creating whole new types at runtime using reflection emit to build the IL representations. […]

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top