2009-08-15 1 views
4

Я генерирую (используя System.Reflection.Emit) два типа: назовите их foo, bar. Ловушка, foo создает экземпляр и вызывает bar, а bar использует foo.два TypeBuilders, называющих друг друга незаконными?

Все работает нормально, когда я создаю бар, но когда я начинаю генерировать foo, я получаю typeloadexception, говоря, что тип foo не может быть найден. Это случается (вероятно, поскольку ошибка была неопределенной), когда я пытаюсь найти конструктор в bar, который как один из его параметров принимает foo.

Это работает, когда бар вложен в тип foo.

Так что мой вопрос: неправомерно ли иметь два типа, называющих друг друга подобным образом, или я делаю это неправильно?

ответ

2

Попытка найти конструктор вручную может быть трудной, но вы все равно должны иметь тот, который вы создали ранее? Вы пробовали передать это? Я постараюсь сделать пример ...

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

Я мог бы добавить дополнительный код, чтобы проверить результат, но проще всего посмотреть на obj в отладчике, и вы можете увидеть поля и т.д.

для более сложных случаев - не забывайте, что вам не нужно писать тела метода (IL), чтобы использовать его ... вы можете написать все подписи первых (DefineMethod, DefineConstructor, и т.д.), а затем записать все тела после, разрешая полностью циклический код.

+0

Оказывается, ошибка лежала где-то в другом месте. Метод, который bar, вызываемый в foo, был защищен, поэтому жизнь была хорошей, когда бар был вложен в foo, когда я переместил его, он не смог вызвать этот метод. Я снова сменил его на публику и на жизнь. Оказывается, SRE и 2am не смешиваются. Спасибо в любом случае. –