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

使用DynamicMethod调用值类型方法(如Int64.ToString())的问题

解决DynamicMethod调用值类型实例方法的问题

这个问题的核心在于值类型装箱后的处理逻辑缺失:当你把值类型(比如Int64)传入FastInvokeHandler的target参数时,值类型会被自动装箱为object。但你的动态IL代码里直接使用了Ldarg_0(装箱后的对象引用)来调用值类型的实例方法,而值类型的实例方法需要操作的是值本身,不是装箱后的引用,这就导致方法实际被调用在了装箱对象的指针上,返回了错误的结果。

修复方案

在生成IL代码时,针对非静态方法,判断目标类型是否为值类型,如果是,需要先对target参数执行解箱操作,拿到值类型的实例地址后再调用方法。

修改GetMethodInvoker方法中处理非静态方法实例的代码段:

原来的代码:

if (!methodInfo.IsStatic) {
    il.Emit(OpCodes.Ldarg_0);
}

修改为:

if (!methodInfo.IsStatic) {
    il.Emit(OpCodes.Ldarg_0);
    // 针对值类型,解箱获取其实例地址
    if (methodInfo.DeclaringType.IsValueType) {
        il.Emit(OpCodes.Unbox, methodInfo.DeclaringType);
    }
}

为什么这样能解决问题?

  • 对于引用类型(比如Person),Ldarg_0直接拿到对象引用,Callvirt可以正常调用实例方法,和原来的逻辑一致。
  • 对于值类型,装箱后的object是一个包含值类型实例的包装对象,Unbox指令会获取到值类型实例的内存地址,值类型的实例方法正是通过这个地址来操作值本身的,这样ToString()就会正确作用在Int64的值上,而不是装箱对象的指针。

修改后的测试效果

当你运行TestInvokeToString时,控制台会输出:

1 converted is 1

完全符合预期。

补充说明

如果你的代码需要支持更多值类型的复杂方法(比如带ref/out参数的),当前的本地变量处理逻辑已经能应对,因为你已经在处理参数时做了Unbox_Any的转换,这次修改只是补上了目标实例的解箱逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 17:22:54