如何使用 emit 从单例调用实例方法



我有例外:操作可能会破坏运行时的稳定性,我不知道为什么:(。请帮助我。

我添加了本地,但仍然无法正常工作...

方法想要动态创建 (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;
    }

您正在复制的方法和您正在创建的方法之间存在差异:前者返回int,后者返回void。这正是您的代码不起作用的原因:当您从 void 方法返回时,堆栈必须是空的;当您从非void方法返回时,堆栈必须包含要返回的值(而不是其他任何内容)。

了解此类问题的最佳方法是在动态程序集的类型中创建方法,将该程序集保存到磁盘,然后对其运行 PEVerify。

若要解决此问题,可以将要创建的方法的返回类型更改为 int 。另一种选择是将方法保持void,但在ret之前将元素pop堆栈上。


话虽如此,我真的不明白你在这里想要完成什么。您的 C# 方法已经完全满足了您的需求,无需为此使用 Reflection.Emit。如果要使用 Reflection.Emit 来避免使用反射的性能损失,则不能只使用 IL 中的反射。

最新更新