2014-12-30 1 views
0

Я создаю динамический тип с этим:Как мне вызвать функцию из переменной в классе, созданном с помощью Reflection.Emit?

AssemblyName assemblyName = new AssemblyName("LunarDynamicAssembly"); 
AssemblyBuilder _assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
ModuleBuilder _moduleBuilder = _assembly.DefineDynamicModule("DynamicModule", true); 

TypeBuilder typeBuilder = _moduleBuilder.DefineType(original.Name + "Proxy", TypeAttributes.Public | TypeAttributes.Class, original, new Type[] { typeof(IProxy) }); 

// - This function only implements the IProxy interface and returns the private variable field. 
FieldBuilder _interceptor = ImplementIProxy(typeBuilder); 
ConstructorInfo _interceptorConstructor = typeof(Interceptor).GetConstructor(Type.EmptyTypes); 

foreach (ConstructorInfo constructorInfo in original.GetConstructors()) 
{ 
    //Omitting for brev. 
    //Recreating all the constructors and ensuring there's a line 
    //_interceptor = new Interceptor(); 
    //in all of them. 
} 

foreach (PropertyInfo pInfo in original.GetProperties(BindingFlags.Public | BindingFlags.Instance)) 
{ 
    MethodInfo getMethod = pInfo.GetGetMethod(); 
    MethodInfo setMethod = pInfo.GetSetMethod(); 

    PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(pInfo.Name, pInfo.Attributes, pInfo.PropertyType, null); 

    MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot; 
    MethodBuilder getBuilder = typeBuilder.DefineMethod(getMethod.Name, attributes, pInfo.PropertyType, null); 
    ILGenerator getIL = getBuilder.GetILGenerator(); 

    // - Issues start here 
    getIL.Emit(OpCodes.Ldarg_0); 
    getIL.Emit(OpCodes.Ldloc, _interceptor); 
    getIL.Emit(OpCodes.Callvirt, typeof(Interceptor).GetMethod("InterceptingFunction")); 
    getIL.Emit(OpCodes.Stloc_0); 
    getIL.Emit(OpCodes.Ldloc_0); 

    getIL.Emit(OpCodes.Ret); 

    typeBuilder.DefineMethodOverride(getBuilder, getMethod); 
} 

InterceptingFunction возвращает тот же тип, что и собственность. Я предполагаю, что мне не хватает того, как поставить «экземпляр» до того, как я вызову функцию, из того, что я проверил в ILDasm. Как я могу это сделать?

Исключение: Common Language Runtime обнаружил недействительную программу.

(Edit) Подробнее Ил код функции, которая делает то, что я пытаюсь создать (для возврата 20 части):

// Code size  20 (0x14) 
.maxstack 1 
.locals init ([0] int32 CS$1$0000) 
IL_0000: nop 
IL_0001: ldarg.0 
IL_0002: ldfld  class [Test]Test.DataAccess.Interceptor Tests.MyClass::_interceptor 
IL_0007: callvirt instance void [Test]Test.DataAccess.Interceptor::InterceptingFunction() 
IL_000c: nop 
IL_000d: ldc.i4.s 20 
IL_000f: stloc.0 
IL_0010: br.s  IL_0012 
IL_0012: ldloc.0 
IL_0013: ret 
+0

Поместите свой код в try catch и проверьте трассировку стека исключений. –

+0

@ gp. Это значит, что InnerException отсутствует, а трассировка стека отображается в MyClassProxy.get_ClassID() в Tests.Program.Main (String [] args) в e: \ Projects \ Tests \ Program.cs: строка 19' – Danicco

+2

IL-код показывает Тип возврата InterceptFunction недействителен. Я попробовал подобный образец и часть «instace» перед вызовом функции не проблема. Проверьте подпись InterceptFunction. Сохраните динамическую сборку, затем проверьте с помощью 'peverify' –

ответ

1

Контрастом

getIL.Emit(OpCodes.Ldloc, _interceptor); 

с

ldfld  class [Test]Test.DataAccess.Interceptor Tests.MyClass::_interceptor 

инструкция ldloc инструкция i s для loading locals, to загрузить поле, вам необходимо использовать ldfld.

Вы также не сделали declare any local variables, но вы все равно пытаетесь использовать его (stloc.0, ldloc.0). Хотя в вашем случае эта локальная переменная совершенно не нужна, вы можете просто оставить значение, возвращенное из InterceptingFunction в стеке. (Рабочий IL делает это, чтобы помочь отлаживать, я верю, что эти дополнительные инструкции, а также ненужная ветка не будут присутствовать в режиме Release.)

Смежные вопросы