c# - 泛型集合中的多态类型参数

标签 c# generics

为什么 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

如果你想做的事情被允许,可以添加一个 AB 的列表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/

相关文章:

c# - 一种 catch 现代编程技术的方法

c# - 仅来自 Sharepoint 列表的自定义字段

c# - 为什么循环列表时此代码会抛出 'InvalidOperationException'?

c# - 减少通用参数

c# - 通用参数不可分配

generics - 是否可以自动实现将一个特征对象转换为另一个特征对象的特征?

java - 如何处理 Java 方法中变量的类型泛型?

c# - System.PlatformNotSupportedException 仅在作为 docker 镜像运行时引用 System.Data.SqlClient

c# - 在 RabbitMQ 中获取一个交换器的所有队列

c# - 将通用类绑定(bind)到特定接口(interface)