为什么 C# 编译器不允许泛型集合(即 List[T])中的多态类型 (T) 参数?
以类'A'和'B'为例,其中'B'是'A'的子类
class A { }
class B : A { }
并考虑一个接受“A”类型列表的函数
void f(List<A> aL) { }
用“B”类型的列表调用
List<B> bL = new List<B>();
f(bL);
报错如下
ERROR: cannot convert from List<B> to List<A>
违反了什么语义规则?
除了循环遍历和转换每个元素(请给我一些糖)之外,还有一个“优雅”的意思吗?谢谢。
最佳答案
List<B>
根本不是 List<A>
的子类型. (我永远不确定在这种情况下什么是“协变”和什么是“逆变”,所以我会坚持使用“子类型”。)考虑一下你这样做的情况:
void Fun(List<A> aa) {
aa(new A());
}
var bb = new List<B>();
Fun(bb); // whoopsie
如果你想做的事情被允许,可以添加一个 A
到 B
的列表s 这显然不是类型安全的。
现在,显然可以安全地读取 列表中的元素,这就是 C# 允许您创建 covariant (i.e. "read-only") interfaces 的原因- 让编译器知道不可能通过它们造成这种损坏。如果您只需要读取权限,对于集合,通常是 IEnumerable<T>
,因此在您的情况下,您可能只是制作方法:
void Fun(IEnumerable<A> aa) { ... }
并使用Enumerable
方法 - 如果基础类型是 List
,大多数应该被优化.
不幸的是,由于 C# 泛型的工作原理,类 根本不能变体,只能是接口(interface)。据我所知,所有的集合接口(interface)都比IEnumerable<T>
“丰富”。是“读写”。从技术上讲,您可以制作自己的协变包装器接口(interface),它只公开您想要的读取操作。
关于c# - 泛型集合中的多态类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17952546/