逆方差/协方差和嵌套泛型



我有一个关于打字和反/反/covairance的问题。

给定以下类

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

最新更新