如何在C#中转换泛型包装类中的派生类实例
解决Wrapper到Wrapper的转换问题
问题原因
C#中默认的泛型类是不变的——即使Y继承自X,Wrapper<Y>和Wrapper<X>也会被视为完全独立的类型,因此无法直接隐式转换,这就是报错CS0029的原因。
解决方案:使用协变泛型接口
C#允许泛型接口/委托通过out关键字实现协变,只要泛型参数仅作为输出类型(如方法返回值)使用,就能安全地实现子类泛型实例到父类泛型实例的转换。
修改代码如下:
using System; class X {} class Y: X {} // 定义协变接口,用out标记泛型参数T interface IWrapper<out T> where T : X {} // 让原Wrapper类实现该协变接口 class Wrapper<T> : IWrapper<T> where T : X {} public class HelloWorld { public static void Main(string[] args) { Wrapper<Y> y = new(); // 现在可以隐式转换为IWrapper<X> IWrapper<X> x = y; } }
注意事项
- 协变的
out关键字要求泛型参数T只能出现在输出位置(比如方法返回值、只读属性),不能作为方法的输入参数(如void SetItem(T item)这类方法会导致协变无法生效)。 - 如果必须保留
Wrapper<X>的类类型而非接口,也可以在Wrapper<T>中实现显式转换方法,但协变接口是更符合C#类型系统设计的优雅方案。
内容的提问来源于stack exchange,提问作者kennarddh
相关产品推荐
相关产品推荐

