Due tipi Costruttori chiamando l'altro illegale?
-
16-09-2019 - |
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
?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.