2009-08-15 8 views
4

Je génère (en utilisant System.Reflection.Emit) deux types: appelez-les foo, bar. Le catch est, foo instancie et appelle la barre, et la barre utilise foo.deux TypeBuilders appelant l'autre illégale?

Tout fonctionne très bien quand je crée une barre, mais quand je commence à générer foo, je reçois typeloadexception en disant que le type foo n'a pas pu être trouvé. Cela arrive (probablement, comme l'erreur était vague) quand j'essaye de localiser le constructeur à la barre, qui comme l'un de ses paramètres prend foo.

Cela fonctionne lorsque la barre est imbriquée tapez foo. Donc, ma question est - est-il illégal d'avoir deux types qui s'appellent comme ça, ou est-ce que je me trompe?

Répondre

2

Essayer de localiser le constructeur manuellement peut être difficile, mais vous devriez toujours avoir celui que vous avez généré plus tôt? Avez-vous essayé de le passer celui-là? Je vais essayer de faire un exemple ...

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); 

Je pourrais ajouter du code supplémentaire pour vérifier le résultat, mais il est plus facile de regarder obj dans le débogueur, et vous pouvez voir les champs, etc.

pour les cas plus complexes - ne pas oublier que vous n'avez pas besoin d'écrire le corps d'une méthode (iL) pour l'utiliser ... vous pouvez écrire toutes les signatures premières (DefineMethod, DefineConstructor, etc.), puis écrire tous les corps après, permettant le code entièrement cyclique.

+0

Il s'avère que l'erreur s'est située ailleurs. La méthode que bar appelait foo, était protégée, donc la vie était bonne quand la barre était imbriquée dans foo, quand je l'ai déplacée, elle n'était pas capable d'appeler cette méthode. Je l'ai changé pour le public et la vie est de nouveau bon. Il s'avère que SRE et 2am ne se mélangent pas. Merci quand même. –