Toying with making a compiler for my own language, I'm trying to generate some MSIL code using the Reflection.Emit framework. It works fine when using int when I declare local variables. However, when I want to declare a local variable of a type I have not yet compiled I get into trouble since the DeclareLocal() takes a Type as argument. That is my uncompiled class, say A, still needs to be defined using
assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemName, AssemblyBuilderAccess.RunAndSave);
module = assemblyBuilder.DefineDynamicModule(Filename);
module.DefineType(name, TypeAttributes.Public | TypeAttributes.Class)
So how will I ever be able to compile the following program
class A {
void M() { B b = new B(); }
}
class B
void M() { A a = new A(); }
}
The primary insight you need here is that TypeBuilder derives from Type. So, even if you didn't finalize a type yet (by calling CreateType()), you can use it to declare a local variable in another type.
One more barrier I encountered is that GetConstructor() on an unfinished TypeBuilder doesn't work (it throws an exception). But if you create the default constructor explicitly, you can call it through the ConstructorBuilder.
static void Main()
{
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("foo"), AssemblyBuilderAccess.RunAndSave);
var module = assemblyBuilder.DefineDynamicModule("foo.dll");
var aType = module.DefineType(
"A", TypeAttributes.Public | TypeAttributes.Class);
var bType = module.DefineType(
"B", TypeAttributes.Public | TypeAttributes.Class);
var aCtor = aType.DefineDefaultConstructor(MethodAttributes.Public);
var bCtor = bType.DefineDefaultConstructor(MethodAttributes.Public);
CreateMethodM(aType, bType, bCtor);
CreateMethodM(bType, aType, aCtor);
aType.CreateType();
bType.CreateType();
assemblyBuilder.Save("foo.dll");
}
static void CreateMethodM(
TypeBuilder thisType, Type otherType, ConstructorInfo otherCtor)
{
var method = thisType.DefineMethod(
"M", MethodAttributes.Private, typeof(void), Type.EmptyTypes);
var il = method.GetILGenerator();
var local = il.DeclareLocal(otherType);
il.Emit(OpCodes.Newobj, otherCtor);
il.Emit(OpCodes.Stloc, local);
il.Emit(OpCodes.Ret);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With