繁体   English   中英

IL使用Reflection.Emit调用带有2个数组参数的方法

[英]IL Calling a method with 2 array arguments using Reflection.Emit

首先,我必须为IL成为菜鸟而言。 我无法生成IL代码来调用具有此签名的方法:

public void CallMethod2(string name, object[] args, object[] genericArgs)

我能够调用一个具有单个数组的方法,如下所示:

public void CallMethod1(string name, object[] args)

使用以下IL工作:

ILGenerator ilgen = myMethod.GetILGenerator();
var il = ilgen;
MethodInfo invokerMethod = typeof(Proxy<T>).GetMethod("CallMethod1", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Ldloc_0);

il.Emit(OpCodes.Call, invokerMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);

但后来我使用以下IL尝试使用此IL调用CallMethod2:

ILGenerator ilgen = myMethod.GetILGenerator();
var il = ilgen;
MethodInfo invokerMethod = typeof(Proxy<T>).GetMethod("CallMethod2", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stelem_Ref);

il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stelem_Ref);

il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc_2);

il.Emit(OpCodes.Call, invokerMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);

此IL与附加对象[]我收到错误:

Common Language Runtime检测到无效程序。

正如你所看到的,我所做的就是添加第二个块来填充数组并调用方法,似乎通过使用StLoc_1它只会破坏它。

我编写了相同的方法并正常调用它并查看了ILDasm,代码似乎全部占用了。

谢谢

我认为问题是这些行就在方法调用之前:

il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc_2);

应该

il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldloc_1);

您的数组位于堆栈位置0和1,而不是1和2。

我很困惑......你明白了:因为你没有真正分配任何本地人,所以代码不应该工作 ; 例如,这里有一个写得不好(因为它使用了不必要的本地人)乘以4的方法,它没有声明本地人:

    var method = new DynamicMethod("MulBy4", typeof (int),
         new Type[] {typeof (int)});
    var il = method.GetILGenerator();
    il.Emit(OpCodes.Ldc_I4_4);
    il.Emit(OpCodes.Stloc_0); // this usage is 
    il.Emit(OpCodes.Ldloc_0); // deliberately silly
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Mul);
    il.Emit(OpCodes.Stloc_1); // this usage is 
    il.Emit(OpCodes.Ldloc_1); // deliberately silly
    il.Emit(OpCodes.Ret);
    var mulBy4= (Func<int,int>)method.CreateDelegate(typeof (Func<int, int>));
    var twelve = mulBy4(3);

这会创建VerificationException

操作可能会破坏运行时的稳定性。

因为它无法验证。 这是不好的IL! 如果我们将其更改为:

    var method = new DynamicMethod("MulBy4", typeof (int),
         new Type[] {typeof (int)});
    var il = method.GetILGenerator();
    il.DeclareLocal(typeof (int));
    il.DeclareLocal(typeof(int));
    ...

然后它现在有效。 然后通过存储和使用从DeclareLocal返回的LocalBuilder ,这将导致记住数字的替代方法:

    var method = new DynamicMethod("MulBy4", typeof (int),
         new Type[] {typeof (int)});
    var il = method.GetILGenerator();
    var multiplier = il.DeclareLocal(typeof (int));
    var result = il.DeclareLocal(typeof(int));
    il.Emit(OpCodes.Ldc_I4_4);
    il.Emit(OpCodes.Stloc, multiplier);
    il.Emit(OpCodes.Ldloc, multiplier);
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Mul);
    il.Emit(OpCodes.Stloc, result);
    il.Emit(OpCodes.Ldloc, result);
    il.Emit(OpCodes.Ret);
    var mulBy4= (Func<int,int>)method.CreateDelegate(typeof (Func<int, int>));
    var twelve = mulBy4(3);

如果您担心这会使用较长的IL版本,那么您可以使用:

static void LoadLocal(this ILGenerator il, LocalBuilder local)
{
    switch(local.LocalIndex)
    {
        case 0: il.Emit(OpCodes.Ldloc_0); break;
        case 1: il.Emit(OpCodes.Ldloc_1); break;
        case 2: il.Emit(OpCodes.Ldloc_2); break;
        case 3: il.Emit(OpCodes.Ldloc_3); break;
        default:
            if(local.LocalIndex < 256)
            {
                il.Emit(OpCodes.Ldloc_S, (byte) local.LocalIndex);
            } else
            {
                il.Emit(OpCodes.Ldloc, (ushort) local.LocalIndex);
            }
            break;
    }
}

il.LoadLocal(multiplier); il.LoadLocal(result); (显然类似于Stloc

我已经更新了@Mark的答案来覆盖价值类型。 StoreLocal是奖金:)

public static void LoadLocalValue(this ILGenerator il, LocalBuilder local)
{
    switch (local.LocalIndex)
    {
        case 0: il.Emit(OpCodes.Ldloc_0); break;
        case 1: il.Emit(OpCodes.Ldloc_1); break;
        case 2: il.Emit(OpCodes.Ldloc_2); break;
        case 3: il.Emit(OpCodes.Ldloc_3); break;
        default:
            if (local.LocalIndex < 256)
            {
                il.Emit(OpCodes.Ldloc_S, (byte)local.LocalIndex);
            }
            else
            {
                il.Emit(OpCodes.Ldloc, (ushort)local.LocalIndex);
            }
            break;
    }
}

public static void LoadLocalAddress(this ILGenerator il, LocalBuilder local)
{
    if (local.LocalIndex < 256)
    {
        il.Emit(OpCodes.Ldloca_S, (byte)local.LocalIndex);
    }
    else
    {
        il.Emit(OpCodes.Ldloca, local);
    }
}

public static void LoadLocalAuto(this ILGenerator il, LocalBuilder local)
{
    if (local.LocalType?.IsValueType == true)
    {
        LoadLocalAddress(il, local);
        return;
    }
    LoadLocalValue(il, local);
}

public static void StoreLocal(this ILGenerator il, LocalBuilder local)
{
    switch (local.LocalIndex)
    {
        case 0: il.Emit(OpCodes.Stloc_0); break;
        case 1: il.Emit(OpCodes.Stloc_1); break;
        case 2: il.Emit(OpCodes.Stloc_2); break;
        case 3: il.Emit(OpCodes.Stloc_3); break;
        default:
            if (local.LocalIndex < 256)
            {
                il.Emit(OpCodes.Stloc_S, (byte)local.LocalIndex);
            }
            else
            {
                il.Emit(OpCodes.Stloc, (ushort)local.LocalIndex);
            }
            break;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM