C#泛型委托强制转换报错原因及中转object与CreateDelegate方案对比
问题解答
1. 为什么委托直接强制转换不生效
C#的委托是名义类型,而非结构类型:即使两个委托的签名完全一致,只要定义时的类型名不同(比如示例中的A和B),就是完全独立的两个类型,不存在任何继承或默认转换关系。
而你使用的泛型方法中,仅给TDelegate添加了Delegate基类约束,编译器在编译泛型方法时,无法确认TDelegate和A之间存在合法的转换路径,因此直接编写(A)delegateToCall会触发编译期检查错误。
你先转object再转A的写法能通过编译,是因为编译器允许任意引用类型转为object,也允许从object显式转为任意引用类型,只是把类型兼容性检查延迟到了运行时执行。
2. 中转object转换方案的隐患
两种方案的适用场景完全不同,隐患只存在于使用场景不匹配的情况:
场景1:你已经通过分支判断确认TDelegate与目标委托类型完全一致
对应你示例代码中if (typeof(TDelegate) == typeof(A))的分支,中转object的方案没有任何隐患:
- 运行时类型检查必然通过,不会抛出转换异常
- 天然保留原委托的多播调用列表,不需要额外处理合并逻辑
- 性能比
CreateDelegate更好,不需要创建新的委托实例,只是做类型转换
场景2:你需要将签名相同但类型不同的委托转为目标类型(比如把B类型的委托转为A调用)
这种场景下中转object的方案完全不可用,运行时会直接抛出InvalidCastException:因为B类型的委托实例本质就不是A类型,即使中转object也无法完成转换。
此时只能使用CreateDelegate方案:它不要求原委托和目标委托类型相同,只要签名匹配就能创建出目标类型的新委托实例,唯一的额外成本是需要自己遍历多播委托的调用列表,逐个创建新委托再合并。
内容的提问来源于stack exchange,提问作者Dixy
相关产品推荐
相关产品推荐

