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

Unity中CreateDelegate绑定首参后Invoke调用参数异常问题

问题原因分析

你遇到的参数错乱问题,核心是误用了Delegate.CreateDelegate的重载。你调用的CreateDelegate(Type, object, MethodInfo)这个重载,设计初衷是给实例方法绑定this指针的:传入的object会作为实例方法的this,而不是方法的第一个参数。但你的Method1和Method2都是静态方法,静态方法没有this指针,所以这个重载根本不会帮你把mt1arg1/mt2arg1绑定为方法的第一个参数,反而会打乱整个参数传递逻辑:

  • 对Method1来说,调用Invoke("xyz")时,程序会错误地把"xyz"当成第一个参数(char类型),而你传入的'c'完全没被用上,乱码就是字符串强制转char时的错误结果。
  • 对Method2来说,传入的AuxSegment会被粗暴拆分:取它的p1作为第一个参数(Vector2),剩下的内存区域乱凑成第二个参数,导致输出完全错位。

而DynamicInvoke之所以能正常工作,是因为它会在运行时动态解析参数列表,相当于绕过了编译时的类型检查,“碰巧”匹配上了方法的参数顺序,但这种方式性能极差,不适合生产环境。


解决方案(无需DynamicInvoke)

下面给你几种高效且类型安全的解决方式,按推荐程度排序:

方案1:Lambda闭包(最简单直观)

直接用Lambda表达式捕获第一个参数,生成符合TDelegate<T, T2>的委托。这种方式是编译时类型检查,性能和直接调用方法完全一致,代码也最简洁:

// 替换原来的del1和del2创建代码
var del1 = new TDelegate<bool, string>(arg2 => Method1(mt1arg1, arg2));
var del2 = new TDelegate<bool, AuxSegment>(arg2 => Method2(mt2arg1, arg2));

修改后再调用Invoke,输出就会和DynamicInvoke完全一致,参数传递准确无误。

方案2:表达式树编译(适合反射场景)

如果你的方法是通过反射动态获取的(而非直接引用),可以用System.Linq.Expressions构建表达式树,编译成目标委托。这种方式性能接近直接调用,远高于DynamicInvoke:

using System.Linq.Expressions;

// 绑定Method1
var method1Info = typeof(YourClassName).GetMethod(nameof(Method1));
var arg2Param = Expression.Parameter(typeof(string), "arg2");
var arg1Const = Expression.Constant(mt1arg1);
var callExpr = Expression.Call(method1Info, arg1Const, arg2Param);
var del1 = Expression.Lambda<TDelegate<bool, string>>(callExpr, arg2Param).Compile();

// 绑定Method2
var method2Info = typeof(YourClassName).GetMethod(nameof(Method2));
var arg2Param2 = Expression.Parameter(typeof(AuxSegment), "arg2");
var arg1Const2 = Expression.Constant(mt2arg1);
var callExpr2 = Expression.Call(method2Info, arg1Const2, arg2Param2);
var del2 = Expression.Lambda<TDelegate<bool, AuxSegment>>(callExpr2, arg2Param2).Compile();

注意把YourClassName替换成你实际的类名。

方案3:封装泛型工具类(复用场景)

如果需要多次绑定不同方法的第一个参数,可以封装一个泛型工具类,复用绑定逻辑:

public static class DelegateBinder
{
    public static TTargetDelegate BindFirst<TTargetDelegate, T1, T2, TResult>(
        Func<T1, T2, TResult> method, T1 firstArg)
        where TTargetDelegate : Delegate
    {
        return (TTargetDelegate)(Delegate)new Func<T2, TResult>(arg2 => method(firstArg, arg2));
    }
}

// 使用示例
var del1 = DelegateBinder.BindFirst<TDelegate<bool, string>, char, string, bool>(Method1, mt1arg1);
var del2 = DelegateBinder.BindFirst<TDelegate<bool, AuxSegment>, Vector2, AuxSegment, bool>(Method2, mt2arg1);

这种方式可以让你在多个地方快速复用绑定逻辑,保持代码整洁。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:32:18