理解非法泛型强制转换

本文关键字:转换 泛型 非法 | 更新日期: 2023-09-27 18:14:44

我很难理解为什么我执行的强制转换会抛出运行时异常,说明它是非法的强制转换。我做了一些研究,找到了这个答案,这让我看到了MSDN文章泛型中的协方差和逆变变。但是,我仍然有点困惑,所以如果有人能帮助澄清,我将不胜感激。

下面是两个类类型的对象层次结构:

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;

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

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

理解非法泛型强制转换

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提供派生程度较低的类型。这叫做逆变。然后,方法的输入参数将获得预期的更派生的类型,这是可以的。