C#泛型继承类出现Generic Type conversion error类型转换错误
问题产生原因
这个报错是C#泛型类型系统的默认规则导致的:
- C#中泛型类的类型参数默认不支持协变:即使
UIMenuView派生自UIView,UIController<UIMenuView>和UIController<UIView>也是两个完全独立的封闭构造类型,二者不存在继承或引用转换关系,无法直接通过as关键字做类型转换。 - 协变特性仅支持在泛型接口、泛型委托上通过
out关键字显式声明,泛型类本身不支持声明协变,这就是现有代码编译失败的核心原因。
编译报错原文:
Cannot convert type 'MenuController' to 'UI.UIController<UI.UIView>'
via a reference conversion, boxing conversion, unboxing conversion,
wrapping conversion, or null type conversion [Assembly-CSharp]
修复方法
可根据框架设计需求选择任意一种方案:
方案1:泛型方法实现(无侵入,推荐)
不需要修改现有视图、控制器基类定义,直接把SetController改成带类型约束的泛型方法,绕开类型转换问题:
void main() { var menuController = new MenuController(); // 无需做as转换,直接传参即可 SetController(menuController); } // 加泛型约束,兼容所有绑定UIView子类的控制器实例 public void SetController<T>(UIController<T> controller, bool asRoot = false) where T : UIView { // 方法内部逻辑正常编写即可 }
该方案为编译期类型安全实现,不会出现运行时类型转换错误,是这类MVC框架场景最常用的实现方式。
方案2:声明协变接口
如果框架需要统一用基类泛型参数接收、存储不同类型的控制器实例,可以额外定义支持协变的泛型接口,让控制器基类实现该接口,方法参数用接口类型接收:
// 用out关键字声明T为协变类型参数 public interface IUIController<out T> where T : UIView { // 注意:协变类型参数只能作为方法返回值类型使用,不能作为方法入参类型 } public class UIController<T> : IUIController<T> where T : UIView { }
对应修改调用逻辑与方法定义:
void main() { var menuController = new MenuController(); SetController(menuController as IUIController<UIView>); } public void SetController(IUIController<UIView> controller, bool asRoot = false) { }
该方案适合需要将不同类型控制器统一放到IUIController<UIView>类型集合中做批量管理的场景。
内容的提问来源于stack exchange,提问作者Nik Mazza
相关产品推荐
相关产品推荐

