13.CSharp泛型写法问题
13.1 题目
这句C#代码是否有问题,为什么?
csharp IList<IList<int>> list = new List<List<int>>();
13.2 深入解析
这句代码编译会报错
举例说明:
如果允许以下代码:
IList<IList<int>> list = new List<List<int>>();
那么通过 IList<IList<int>> 视图向其中添加「任意 IList<int>」时,可能加入并非 List<int> 的实例,破坏底层 List<List<int>> 的类型约定。例如(仅作类型安全说明,实际因不变性上述赋值无法编译):
// 若错误地允许协变:`int[]` 实现 IList<int>,但并非 List<int>
list.Add(new int[10]);
原因:泛型协变性和逆变性的问题
协变(Covariance):允许子类型赋值给父类型,通常用于out类型参数;逆变(Contravariance):允许父类型赋值给子类型,通常用于in类型参数。
而 IList<T> 既包含“获取”操作(返回 T,可能需要协变),又包含“设置”操作(接受 T,可能需要逆变),因此它既不能是协变的,也不能是逆变的,只能是不变的。
13.3 答题示例
“这句代码有问题,会导致编译错误。原因在于C#泛型的不变性:
IList<T>接口既包含输出操作(如返回T的this[int]),又包含输入操作(如接受T的Add方法),因此它是不变接口,不支持协变或逆变转换。具体来说,
List<List<int>>不能赋值给IList<IList<int>>——虽然List<int>实现IList<int>,但IList<T>对T是不变的:不能把这种“嵌套泛型”的实例当成外层接口的另一种类型实参。若放宽为可赋值,则可通过IList<IList<int>>的Add传入任意IList<int>(如int[]),而实际容器仍是List<List<int>>,破坏类型一致性。”
13.4 关键词联想
- 泛型不变性(Invariance)
- 协变(Covariance,out关键字)
- 逆变(Contravariance,in关键字)
- 类型安全(Type Safety)
IList<T>双向操作(get/set)- 泛型接口方差(Generic Interface Variance)
IEnumerable<out T>(协变示例)Action<in T>(逆变示例)- 子类型泛型赋值限制
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com