【发布时间】:2015-12-23 12:52:30
【问题描述】:
我无法理解为什么我正在执行的演员表会引发运行时异常,说明这是非法演员表。我做了一些研究,发现了this answer,这使我找到了 MSDN 文章Covariance and Contravariance in Generics。但是,我仍然有点困惑,所以如果有人能帮助澄清,将不胜感激。
这是 2 类类型的对象层次结构:
IMongoEntity (interface)
| - MongoEntity (abstract)
| | -SalesProject (concrete)
| | -ManagementProject (concrete)
IEntityService<T> where T : IMongoEntity (interface)
| -EntityService<T> where T : IMongoEntity (concrete superclass)
| | - MgmtService : EntityService<ManagementProject> (subclass)
| | - SalesService : EntityService<SalesProject> (subclass)
仅创建了两个非通用服务,因此我可以创建一些仅适用于这些特定类型的特定方法(本质上是预定义的数据库查找)。
然后我有这条线,它抛出InvalidCastException:
IEntityService<IMongoEntity> service = fromsales ?
(IEntityService<IMongoEntity>)salesService :
(IEntityService<IMongoEntity>)mgmtService;
既然两个服务都是从同一个接口和抽象类派生的,并且使用的类型参数是从同一个抽象类派生的,那么为什么这种强制转换是非法的呢?
注意:我有解决方法,所以我并不是真的在寻找解决方案,而是想了解为什么这是不允许的。
【问题讨论】:
-
如果
IEntityService<T> where T : IMongoEntity更改为IEntityService<out T> where T : IMongoEntity我认为它会起作用。您正在遇到协方差问题 -
@ScottChamberlain 不是泛型中返回类型的 out 关键字吗?这些方法都返回 Task
或 Task -
想象
IEntityService<T>有一个Add(T item)方法。 (我们不知道它是否这样做,但编译器并不关心。它可以。)现在想想这对IEntityService<IMongoEntity>意味着什么 - 你可以添加 any mongo 实体。现在,您可以将ManagementProject添加到SalesService吗?不... 这就是它无效的原因。 -
@JonSkeet 啊,就是这么简单!这是有道理的。
-
而
out告诉编译器您没有任何Add(T item)调用。