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