Как вызвать метод экземпляра из синглтона с помощью emit

У меня есть исключение: операция может дестабилизировать среду выполнения, и я не знаю, почему :( Пожалуйста, помогите мне.

Я добавил Local, но все еще не работает...

Метод, который нужно создать динамически (REF000001):

public static int REF000001(int REF000002, object REF000003, DateTime REF000004)
    {
        return (int)typeof(REF000005).GetMethod("REF000006", new Type[] { typeof(int), typeof(object), typeof(DateTime) }).Invoke(REF000005.REF000008(), new object[] { REF000002, REF000003, REF000004 });
    }

Это класс, который я хочу вызвать из синглтона.

public class REF000005
{
    private static REF000005 REF000007;

    private REF000005()
    {

    }

    public static REF000005 REF000008()
    {
        if (REF000007 == null)
            REF000007 = new REF000005();

        return REF000007;
    }

    public int REF000006(int REF000009, object REF000010, DateTime REF000011)
    {
        return 5;
    }
}

Возврат из ILDASM:

.method public hidebysig static int32  REF000001(int32 REF000002,
                                             object REF000003,
                                             valuetype [mscorlib]System.DateTime REF000004) cil     managed
{
// Code size       118 (0x76)
.maxstack  5
.locals init ([0] int32 CS$1$0000,
       [1] class [mscorlib]System.Type[] CS$0$0001,
       [2] object[] CS$0$0002)
IL_0000:  nop
IL_0001:  ldtoken    ConsoleApplication3.REF000005
IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000b:  ldstr      "REF000006"
IL_0010:  ldc.i4.3
IL_0011:  newarr     [mscorlib]System.Type
IL_0016:  stloc.1
IL_0017:  ldloc.1
IL_0018:  ldc.i4.0
IL_0019:  ldtoken    [mscorlib]System.Int32
IL_001e:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0023:  stelem.ref
IL_0024:  ldloc.1
IL_0025:  ldc.i4.1
IL_0026:  ldtoken    [mscorlib]System.Object
IL_002b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0030:  stelem.ref
IL_0031:  ldloc.1
IL_0032:  ldc.i4.2
IL_0033:  ldtoken    [mscorlib]System.DateTime
IL_0038:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_003d:  stelem.ref
IL_003e:  ldloc.1
IL_003f:  call       instance class [mscorlib]System.Reflection.MethodInfo [mscorlib]System.Type::GetMethod(string,
                                                                                                          class [mscorlib]System.Type[])
IL_0044:  call       class ConsoleApplication3.REF000005 ConsoleApplication3.REF000005::REF000008()
IL_0049:  ldc.i4.3
IL_004a:  newarr     [mscorlib]System.Object
IL_004f:  stloc.2
IL_0050:  ldloc.2
IL_0051:  ldc.i4.0
IL_0052:  ldarg.0
IL_0053:  box        [mscorlib]System.Int32
IL_0058:  stelem.ref
IL_0059:  ldloc.2
IL_005a:  ldc.i4.1
IL_005b:  ldarg.1
IL_005c:  stelem.ref
IL_005d:  ldloc.2
IL_005e:  ldc.i4.2
IL_005f:  ldarg.2
IL_0060:  box        [mscorlib]System.DateTime
IL_0065:  stelem.ref
IL_0066:  ldloc.2
IL_0067:  callvirt   instance object [mscorlib]System.Reflection.MethodBase::Invoke(object,
                                                                                  object[])
IL_006c:  unbox.any  [mscorlib]System.Int32
IL_0071:  stloc.0
IL_0072:  br.s       IL_0074
IL_0074:  ldloc.0
IL_0075:  ret
} // end of method Program::REF000001

Мой код с исключением генератора IL. Операция может дестабилизировать среду выполнения.

static DynamicMethod Method1A()
    {
        DynamicMethod method1 = new DynamicMethod("Dodaj", typeof(void), new Type[] { typeof(int), typeof(object), typeof(DateTime) });
        ILGenerator il = method1.GetILGenerator();

        Label target = il.DefineLabel();

        var tps = il.DeclareLocal(typeof(Type[]));
        var obs = il.DeclareLocal(typeof(object[]));

        il.Emit(OpCodes.Ldtoken, typeof(REF000005));
        il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) }));
        il.Emit(OpCodes.Ldstr, "REF000006");

        il.Emit(OpCodes.Ldc_I4_3);
        il.Emit(OpCodes.Newarr, typeof(Type));
        il.Emit(OpCodes.Stloc, tps);
        il.Emit(OpCodes.Ldloc, tps);
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Ldtoken, typeof(Int32));
        il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) }));
        il.Emit(OpCodes.Stelem_Ref);
        il.Emit(OpCodes.Ldloc, tps);
        il.Emit(OpCodes.Ldc_I4_1);
        il.Emit(OpCodes.Ldtoken, typeof(Object));
        il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) }));
        il.Emit(OpCodes.Stelem_Ref);
        il.Emit(OpCodes.Ldloc, tps);
        il.Emit(OpCodes.Ldc_I4_2);
        il.Emit(OpCodes.Ldtoken, typeof(DateTime));
        il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) }));
        il.Emit(OpCodes.Stelem_Ref);
        il.Emit(OpCodes.Ldloc, tps);

        il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetMethod", new Type[2] { typeof(string), typeof(Type[]) }));
        il.Emit(OpCodes.Call, typeof(REF000005).GetMethod("REF000008"));

        il.Emit(OpCodes.Ldc_I4_3);
        il.Emit(OpCodes.Newarr, typeof(object));
        il.Emit(OpCodes.Stloc, obs);
        il.Emit(OpCodes.Ldloc, obs);
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Ldarg, 0);
        il.Emit(OpCodes.Box, typeof(Int32));
        il.Emit(OpCodes.Stelem_Ref);
        il.Emit(OpCodes.Ldloc, obs);
        il.Emit(OpCodes.Ldc_I4_1);
        il.Emit(OpCodes.Ldarg, 1);
        //il.Emit(OpCodes.Box, typeof(object));
        il.Emit(OpCodes.Stelem_Ref);
        il.Emit(OpCodes.Ldloc, obs);
        il.Emit(OpCodes.Ldc_I4_2);
        il.Emit(OpCodes.Ldarg, 2);
        il.Emit(OpCodes.Box, typeof(DateTime));
        il.Emit(OpCodes.Stelem_Ref);
        il.Emit(OpCodes.Ldloc, obs);
        il.Emit(OpCodes.Box, typeof(object[]));
        il.Emit(OpCodes.Callvirt, typeof(MethodBase).GetMethod("Invoke", new Type[2] { typeof(object), typeof(object[]) }));
        il.Emit(OpCodes.Unbox_Any, typeof(Int32));
        il.Emit(OpCodes.Ret);
        return method1;
    }

person user2807597    schedule 23.09.2013    source источник
comment
Похоже, вы забыли объявить свои локальные переменные.   -  person svick    schedule 23.09.2013
comment
я добавляю Local и меняю свой код, но все равно не работает. Не могли бы вы помочь мне, пожалуйста.   -  person user2807597    schedule 24.09.2013


Ответы (1)


Существует разница между методом, который вы копируете, и методом, который вы создаете: первый возвращает int, второй void. Именно поэтому ваш код не работает: когда вы возвращаетесь из метода void, стек должен быть пуст; когда вы возвращаетесь из метода, отличного от void, стек должен содержать возвращаемое значение (и ничего больше).

Лучший способ узнать о проблемах такого рода — создать свой метод в виде типа в динамической сборке, сохранить эту сборку на диск, а затем запустить для нее PEVerify.

Чтобы исправить это, вы можете изменить тип возвращаемого значения создаваемого вами метода на int. Другим вариантом было бы сохранить метод void, но pop элемент в стеке прямо перед вами ret.


При этом я действительно не понимаю, чего вы пытаетесь достичь здесь. Ваш метод С# уже делает именно то, что вам нужно, для этого нет необходимости использовать Reflection.Emit. И если вы хотите использовать Reflection.Emit, чтобы избежать потери производительности при использовании отражения, вы не можете просто использовать отражение из своего IL.

person svick    schedule 24.09.2013
comment
@ user2807597 Если вы считаете, что мой ответ действительно ответил на ваш вопрос, вы должны принять его. - person svick; 26.09.2013