泛型协变与类型约束:IContainer<T>为何无法转为IContainer<IContents>?
泛型协变与类型约束的疑问
先看你提供的代码:
public interface IContainer<out T> { } public interface IContents { } public class Food : IContents { } public class Foo { public void Bar<T>() where T : IContents { IContainer<IContents> x = null; IContainer<T> y = null; IContainer<Food> z = null; x = y; // 报错:无法将源类型“IContainer<T>”转换为目标类型“IContainer<IContents>” x = z; // 合法 } }
为什么x = z合法,x = y却报错?
1. x = z合法的原因
Food是明确的引用类型,且实现了IContents。由于IContainer是协变接口(标记了out T),协变规则允许将更具体类型的协变接口实例赋值给更抽象类型的协变接口变量——也就是IContainer<Food>可以安全转换为IContainer<IContents>,编译器能直接确认这个转换的合法性,所以不会报错。
2. x = y报错的原因
泛型参数T的约束仅为where T : IContents,这意味着T的范围很广:它可以是IContents本身、Food这类引用类型实现类,也可以是实现了IContents的值类型结构体。
编译器在处理泛型方法Bar<T>时,无法提前确定T的具体类型:
- 如果
T是引用类型,IContainer<T>到IContainer<IContents>的转换是合法的协变引用转换; - 但如果
T是值类型,这个转换会变成装箱转换,编译器不允许在泛型方法中进行这种不确定的转换(因为泛型方法需要适配所有符合约束的T)。
如果给T加上class约束,明确T必须是引用类型:
public void Bar<T>() where T : class, IContents { IContainer<IContents> x = null; IContainer<T> y = null; x = y; // 此时编译通过 }
编译器就能确认IContainer<T>到IContainer<IContents>的转换是合法的协变引用转换,不再报错。
内容的提问来源于stack exchange,提问作者Khaldin K.S.
相关产品推荐
相关产品推荐

