gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-30 00:34:12 27 4
gpt4 key购买 nike

首先,我必须为自己是 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[] 我得到一个错误:

公共(public)语言运行时检测到无效程序。

如您所见,我所做的只是添加了第二个 block 来填充数组并调用该方法,似乎通过使用 StLoc_1 它只会破坏它。

我编写了相同的方法并正常调用它,然后查看了 ILDasm,代码似乎都捆绑在一起。

谢谢

最佳答案

我很困惑...你看:那个代码不应该工作因为你实际上没有分配任何局部变量;例如,这里有一个写得很糟糕(因为它使用了不必要的局部变量)的乘以 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:

Operation could destabilize the runtime.

因为它无法验证。这是坏的 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 有类似的东西)

关于c# - IL 使用 Reflection.Emit 调用带有 2 个数组参数的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8485988/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com