2012-09-14 12 views
7

Giocando con un compilatore per la mia lingua, sto provando a generare del codice MSIL usando il framework Reflection.Emit. Funziona correttamente quando si utilizza int quando si dichiarano variabili locali. Tuttavia, quando voglio dichiarare una variabile locale di un tipo che non ho ancora compilato, mi trovo nei guai dato che lo DeclareLocal() prende un argomento come Type. Questa è la mia classe non compilato, dire A, deve ancora essere definita utilizzandoILGenerator.DeclareLocal() accetta un tipo di classe non ancora compilata

assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemName, AssemblyBuilderAccess.RunAndSave); 
module = assemblyBuilder.DefineDynamicModule(Filename); 
module.DefineType(name, TypeAttributes.Public | TypeAttributes.Class) 

Così come farò mai in grado di compilare il seguente programma

class A { 
    void M() { B b = new B(); } 
} 
class B 
    void M() { A a = new A(); } 
} 
+0

Cosa sarebbe di aiuto? –

+1

@phoog: potrebbe anche aspettare che qualcuno faccia il suo lavoro, quindi .. –

+0

In realtà non sto facendo C# qui ... era solo un esempio di dipendenza circolare –

risposta

7

L'intuizione primaria è necessario qui è che TypeBuilder deriva da Type. Quindi, anche se non hai ancora finalizzato un tipo (chiamando CreateType()), puoi usarlo per dichiarare una variabile locale in un altro tipo.

Un'altra barriera che ho riscontrato è che GetConstructor() su un incompleto TypeBuilder non funziona (genera un'eccezione). Ma se si crea esplicitamente il costruttore predefinito, è possibile chiamarlo tramite lo 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); 
} 
+1

Argh! La mia soluzione è così vicina alla tua! Sono stato accecato dal voler chiamare "t.DeclaringType" piuttosto che semplicemente "t" –

+2

'DeclaringType' è qualcosa di diverso, rappresenta il tipo in cui è stato dichiarato questo tipo, ad esempio quando è un tipo annidato. – svick

Problemi correlati