You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用OpCodes.Call?DynamicMethod调用方法报错求助

解决DynamicMethod调用实例方法时的InvalidProgramException问题

看起来你遇到的问题是IL栈结构不匹配导致的验证失败,这是因为调用实例方法时缺少了必要的this指针压栈操作,同时你的IL代码里还有多余的指令。我来一步步帮你理清问题并解决:

问题根源分析

  1. 实例方法调用的要求:你的Test是实例方法,调用它必须先把Form1的实例(也就是this指针)压入IL栈,然后再压入方法的参数(int类型的s),最后才能调用方法。
  2. 你的错误操作:你当前的IL代码只压入了DynamicMethod的int参数(Ldarg_0),直接调用实例方法,这导致栈上缺少实例对象,IL验证器直接抛出InvalidProgramException。
  3. 多余的指令:你还保留了Dup和Mul指令,这会把Test方法返回的s*s再相乘一次,得到的是(s*s)^2,这和你最初的功能(计算s*s)不符,应该去掉。

两种解决方案

方案1:将Test改为静态方法(最简单)

静态方法不需要实例对象,直接压入参数就能调用,修改起来最省事:

  1. 先修改Test方法为静态:
public static long Test(int s) {
    return (long)s * s; // 转成long避免int溢出
}
  1. 修改DynamicMethod的IL生成代码:
MethodInfo mi = typeof(Form1).GetMethod("Test", new Type[] { typeof(int) });
ig.Emit(OpCodes.Ldarg_0); // 压入DynamicMethod的int参数
ig.EmitCall(OpCodes.Call, mi, null); // 调用静态Test方法,返回long结果
ig.Emit(OpCodes.Ret); // 直接返回结果

方案2:保留实例方法,传入Form1实例

如果你必须保留Test为实例方法,需要在IL里先加载Form1的实例。这里我们通过静态字段存储当前窗体实例来实现:

  1. 在Form1类里添加一个静态字段:
private static Form1 _currentInstance;
  1. 在Form1_Load里初始化这个字段:
_currentInstance = this;
  1. 修改IL生成代码:
MethodInfo mi = typeof(Form1).GetMethod("Test", new Type[] { typeof(int) });
// 先加载Form1的实例(从静态字段获取)
ig.Emit(OpCodes.Ldsfld, typeof(Form1).GetField("_currentInstance", BindingFlags.NonPublic | BindingFlags.Static));
// 再压入DynamicMethod的int参数
ig.Emit(OpCodes.Ldarg_0);
// 调用实例Test方法
ig.EmitCall(OpCodes.Callvirt, mi, null);
ig.Emit(OpCodes.Ret); // 返回结果

额外提示

  • 如果你确实需要计算(s*s)^2,那可以保留Dup和Mul,但要确保栈上有两个相同的long值(也就是在调用Test之后再执行Dup和Mul)。
  • 调试IL代码时,可以用ILGenerator.EmitWriteLine输出中间值,或者用工具查看生成的IL,方便定位栈结构问题。

内容的提问来源于stack exchange,提问作者PiggyChu001

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:57:45