Domanda

Sono la generazione (usando System.Reflection.Emit) di due tipi: chiamarli foo, bar. La cattura è, foo un'istanza e chiama bar, e la barra usa foo.

Tutto funziona bene quando creo bar, ma quando poi comincio pippo generazione, ottengo TypeLoadException dire che tipo di pippo non è stato trovato. Succede (probabilmente, come l'errore è stato vaga) quando si tenta di individuare il costruttore per Bar, che come uno dei suoi parametri prende foo.

Questo funziona quando la barra è di tipo nidificato in foo.

Quindi la mia domanda è - è illegale avere due tipi di chiamata a vicenda come questa, o sono io che faccio male

?
È stato utile?

Soluzione

Il tentativo di individuare manualmente il costruttore può essere difficile, ma si dovrebbe comunque avere quello generato in precedenza? Hai provato a passarlo che uno? Cercherò di fare un esempio ...

    var assemblyName = new AssemblyName("tmp");
    var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    var module = assembly.DefineDynamicModule("tmp");
    var foo = module.DefineType("Foo");
    var bar = module.DefineType("Bar");
    var barOnFoo = foo.DefineField("bar", bar, FieldAttributes.Private);
    var fooOnBar = bar.DefineField("foo", foo, FieldAttributes.Private);
    var barCtor = bar.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { foo });
    var il = barCtor.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Stfld, fooOnBar);
    il.Emit(OpCodes.Ret);
    var fooCtor = foo.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
    il = fooCtor.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Newobj, barCtor);
    il.Emit(OpCodes.Stfld, barOnFoo);
    il.Emit(OpCodes.Ret);

    // create the actual types and test object creation
    Type fooType = foo.CreateType(), barType = bar.CreateType();
    object obj = Activator.CreateInstance(fooType);

Potrei aggiungere codice aggiuntivo per controllare il risultato, ma è più facile solo per guardare obj nel debugger, e si può vedere i campi ecc.

Per i casi più complessi - non dimenticate che non è necessario scrivere il corpo di un metodo (il IL) per usarlo ... è possibile scrivere tutte le firme prima ( DefineMethod, DefineConstructor, ecc), e quindi scrivere tutti i corpi dopo, consentendo codice completamente ciclico.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top