C#中为何IEnumerable可接收接口实现类列表而List不行
原因解析:C# 泛型协变的约束差异
这个问题本质是C#泛型的协变规则对不同接口/类型的支持不同,核心原因如下:
1. IEnumerable<T> 天然支持协变
C# 4.0引入了泛型协变/逆变特性,分别用out/in关键字标记泛型参数:
IEnumerable<T>的官方定义为public interface IEnumerable<out T> : IEnumerable,其中out标记表示T是协变参数,仅作为接口方法的返回值输出,不会作为入参使用。- 作为只读遍历接口,
IEnumerable<T>只能读取集合元素,无法修改/新增元素,把List<MyClass1>转换为IEnumerable<IMyInterface>完全类型安全,不会出现类型不匹配的问题,因此编译器允许这种转换。
2. List<T> 不支持协变是出于类型安全考虑
List<T>是可读写的可变集合,没有协变标记:
- 如果编译器允许
List<MyClass1>转换为List<IMyInterface>,你就可以在方法内往这个集合里插入任意实现IMyInterface的实例(比如MyClass2对象),这会直接破坏原List<MyClass1>的泛型约束,运行时必然会出现类型转换错误。 - 以下代码可直观体现风险:
void MyFunction(List<IMyInterface> list) { // 语法上完全合法,因为MyClass2实现了IMyInterface list.Add(new MyClass2()); } // 假设允许List<MyClass1>转List<IMyInterface> var myClass1List = new List<MyClass1>(); MyFunction(myClass1List); // 此时myClass1List[0]是MyClass2类型,和List<MyClass1>的定义冲突,取值时直接崩溃
编译器就是为了避免这种运行时风险,才直接禁止了List<T>的协变转换。
内容的提问来源于stack exchange,提问作者Adjit。
相关产品推荐
相关产品推荐

