Suppose you want to use Reflection.Emit to generate a dynamic type in memory. Suppose this dynamic type should inherit a custom base type, and you want to put the default implementation into this base type. In plain C#, you would write…
class MyDynamic : MyBase { public MyDynamic() { } }
… but with Reflection.Emit, there’s a gotcha.
The C# code above shows a class with a default constructor. No base constructor is explicitly called. In this case, the C# compiler automatically adds a call to the base classes default constructor. This is a feature of the compiler, not the CLR! Using Reflection.Emit, you must add the call to the base constructor yourself, since you’re skipping the C# compiler.
If you forget to call the base constructor, the base class won’t work as in regular C# code. You might encounter strange exceptions (probably lots of NullReferenceException or InvalidOperationException).
The following code show how to generate a class with a default constructor that calls its base constructor.
// We want to create a type that inherits "MyBaseType" and calls its default constructor. var baseType = typeof(MyBaseType); var baseConstructor = baseType.GetConstructor(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance, null, new Type[0], null); // Create a Type Builder that generates a type directly into the current AppDomain. var appDomain = AppDomain.CurrentDomain; var assemblyName = new AssemblyName("MyDynamicAssembly"); var assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); var typeBuilder = moduleBuilder.DefineType("MyDynamicType", TypeAttributes.Class | TypeAttributes.Public, baseType); // Create a parameterless (default) constructor. var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null); var ilGenerator = constructor.GetILGenerator(); // Generate constructor code ilGenerator.Emit(OpCodes.Ldarg_0); // push "this" onto stack. ilGenerator.Emit(OpCodes.Call, baseConstructor); // call base constructor ilGenerator.Emit(OpCodes.Nop); // C# compiler add 2 NOPS, so ilGenerator.Emit(OpCodes.Nop); // we'll add them, too. ilGenerator.Emit(OpCodes.Ret); // Return
If you need to pass parameters to the base constructor, you can change the code above as follows:
ilGenerator.Emit(OpCodes.Ldarg_0); // push "this" ilGenerator.Emit(OpCodes.Ldarg_1); // push the 1. parameter ilGenerator.Emit(OpCodes.Ldarg_2); // push the 2. parameter ilGenerator.Emit(OpCodes.Ldarg_3); // push the 3. parameter ilGenerator.Emit(OpCodes.Call, baseConstructor); ilGenerator.Emit(OpCodes.Nop); ilGenerator.Emit(OpCodes.Nop); ilGenerator.Emit(OpCodes.Ret);
This post shows how to add properties to the generated type.
The order of calling is wrong: (constructor)
var ilGenerator = constructor.GetILGenerator();
// Create a parameterless (default) constructor.
var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
Yes, you’re right, I’ll fix that. Thank you, Jeroen.