为何C#中IList<Dog>转IEnumerable<Animal>无需显式转换?
为什么
IEnumerable<Animal> animals = dogs;无需显式转换? 咱们来拆解一下这个问题,核心原因其实是C#里的泛型协变特性,这也是编译器允许直接赋值的关键:
- 首先看
IEnumerable<T>这个接口,它的定义里用了out关键字标记类型参数T,也就是public interface IEnumerable<out T>。这个out就表示这个接口是协变的——简单说,当Dog是Animal的子类时,IEnumerable<Dog>可以被隐式当作IEnumerable<Animal>来使用。 - 再看你的代码:
IList<Dog> dogs = new List<Dog>();,IList<T>接口本身是继承自IEnumerable<T>的,所以dogs这个变量不仅是IList<Dog>,同时也实现了IEnumerable<Dog>。 - 因为协变的存在,
IEnumerable<Dog>可以自动、安全地隐式转换为IEnumerable<Animal>,所以你直接写IEnumerable<Animal> animals = dogs;完全没问题,根本不需要额外的显式转换。
那为什么编译器允许这种操作呢?因为协变是类型安全的:IEnumerable<T>是一个只读的迭代接口,它只能向外输出T类型的元素,不会允许你往里面添加元素。这就保证了不会出现“把一只Cat放进Dog集合”这种类型错误,编译器完全放心让这个转换自动完成。
至于你提到的IEnumerable<Animal> animals = (List<Dog>) dogs;这种显式转换,其实完全没必要——dogs本来就是IList<Dog>类型,强制转成List<Dog>既多余,也不是这个赋值操作能成功的关键,真正起作用的还是IEnumerable<T>的协变特性。
内容的提问来源于stack exchange,提问作者BoSsYyY
相关产品推荐
相关产品推荐

