在 C# 中,数组协变指的是什么?请解释其定义,并说明为什么 C# 的数组被设计为支持协变,以及这种设计带来了哪些潜在风险?
考察说明
考查对 C# 数组类型系统协变机制的理解,包括定义、设计动机及类型安全风险。
回答思路
- 【回答框架 1】数组协变是指如果存在引用类型之间的隐式引用转换,比如从 Derived 到 Base,那么可以将 Derived[] 视为 Base[]。例如,string[] 可以赋值给 object[]。
- 【回答框架 2】C# 设计数组协变是为了兼容 Java 等语言的类似行为,并曾在早期用于某些算法或 API 的通用性,例如 Array.Sort 接受 Array 类型参数,协变使不同具体数组类型能够统一传递。
- 【回答框架 3】协变带来的风险是类型安全漏洞:在编译期允许将 string[] 视为 object[],但在运行时向其中写入 int 等不兼容元素会抛出 ArrayTypeMismatchException。例如,object[] arr = new string[1]; arr[0] = 1; 会触发异常。
- 【回答框架 4】因此,数组协变在 C# 中被认为是一种不安全的设计,微软官方也建议在代码中避免依赖数组协变,而优先使用泛型集合如 IEnumerable<T> 等,来实现类型安全的协变。
- 【关键点 1】数组协变允许 Derived[] 被视为 Base[],前提是存在引用转换。
- 【关键点 2】设计动机包括兼容 Java 和便于通用 API 的实现。
- 【关键点 3】协变破坏了类型安全,运行时写入不兼容类型会抛异常。
- 【关键点 4】应优先使用泛型集合来实现类型安全的协变。
- 【易错点 1】混淆值类型数组的协变,值类型数组(如 int[])不能协变为 object[],但可通过 Array 类型间接传递。
- 【易错点 2】忽略运行时类型检查,导致 ArrayTypeMismatchException。
- 【易错点 3】过度依赖协变,导致代码可读性和类型安全下降。