相反/协方差和嵌套泛型

问题描述

我对打字和反对/协约有疑问。

提供以下课程

public class BoardItemsHolderRepository<THolder,TBoardItem> : DataRepository<IList<THolder>> 
    where TBoardItem : BoardItem
    where THolder : IBoardItemHolder<TBoardItem>
{
}
public interface IDataRepository<T> : IDataGetRepository<T>,IDataSetRepository<T> where T : class
{
}

public interface IDataGetRepository<out T> where T : class
{
    IObservable<T> GetObservableStream();
    IObservable<T> GetMostRecent();
}

public interface IDataSetRepository<in T> where T : class
{
    void Set(T value);
}

public abstract class DataRepository<T> : IDataRepository<T> where T : class
{
  ..implementation details
}
public class ConstructHolder : IBoardItemHolder<Construct>
{
  ..implementation details
}

鉴于上述3个文件,有人可以向我解释为什么会发生以下情况吗?:

IDataGetRepository<IList<IBoardItemHolder<Construct>>> wontCompile = new BoardItemsHolderRepository<ConstructHolder,Construct>(); //illegal
IDataGetRepository<IList<ConstructHolder>> compile = new BoardItemsHolderRepository<ConstructHolder,Construct>();  //legal

我不明白为什么第一行的隐式强制转换不起作用,因为随后的行会编译(按预期)

IBoardItemHolder<Construct>> compile = new ConstructHolder();

解决方法

让我们逐步扩展非法行的右侧。首先,我们从

开始
BoardItemsHolderRepository<ConstructHolder,Construct>

这是DataRepository<IList<THolder>>,因此上面是一种:

DataRepository<IList<ConstructHolder>>

依次为IDataGetRepository<T>,因此以上是一种:

IDataGetRepository<IList<ConstructHolder>>

IDataGetRepository<T>T上是协变的。确切地回忆一下这是什么意思:如果 UT的子类型,那么IDataGetRepository<U>IDataGetRepository<T>的子类型。例如,IDataGetRepository<Cat>IDataGetRepository<Animal>的子类型,因此可以将前一种类型的实例分配给后一种类型的变量。

但是,IDataGetRepository<IList<ConstructHolder>>不是IDataGetRepository<IList<IBoardItemHolder<Construct>>>的子类型,因此无法为其分配。为什么? 因为IList<ConstructHolder>不是IList<IBoardItemHolder<Construct>>的子类型! IList<T>T上是不变的!

因此,根据类型检查器,您尝试做的事情违反了类型安全。也许尝试使用IEnumerable而不是IList

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...