了解非法通用演员

时间:2015-09-25 16:12:38

标签: c# .net generics casting

我很难理解为什么我正在执行的演员投掷运行时异常,说明这是非法演员。我做了一些研究并找到了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;

由于这两种服务都来自相同的接口和抽象类和使用的类型参数是从同一个抽象类派生的,那么为什么这个类型非法?

注意:我有解决方法,所以我不是在寻找解决方案,而是想了解为什么这是不允许的。

1 个答案:

答案 0 :(得分:3)

MyType<Base>MyType<Derived>没有任何继承关系,即使Derived来自Base。两种泛型类型只是两种不同的类型。

解决此问题的一种方法是将非通用接口作为基本接口:

public interface IEntityService
{
    void DoSomething(object item);
}

public interface IEntityService<T> : IEntityService
{
    void DoSomething(T item);
}

此模式用于.Net类库(例如IEnumerable / IEnumerable<T>IList / IList<T>)。

如果您知道您的界面仅对输出使用通用类型(T),则可以使用out关键字IMyInterface<out T>。然后,您可以为T提供更多派生类型。这称为协方差。然后,方法的返回值将产生消费者所期望的更多派生类型,这是可以的。

如果它仅对输入使用通用类型,请使用in关键字IMyInterface<in T>。然后,您可以为T提供较少派生的类型。这称为逆变。然后,方法的输入参数将按预期获得更多派生类型,这是可以的。