Contra/covariance 和嵌套泛型

Contra/covariance and nested generics

我有一个关于打字的问题 contra/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!

上不变

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