Reputation: 149
I have a question on typing and contra/covairance.
Given the following classes
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
}
Given the above 3 files, can someone explain to me why is the following happening?:
IDataGetRepository<IList<IBoardItemHolder<Construct>>> wontCompile = new BoardItemsHolderRepository<ConstructHolder, Construct>(); //illegal
IDataGetRepository<IList<ConstructHolder>> compile = new BoardItemsHolderRepository<ConstructHolder, Construct>(); //legal
I can't understand why implicit casting for the first line would not work, as the following line compiles(as expected)
IBoardItemHolder<Construct>> compile = new ConstructHolder();
Upvotes: 1
Views: 158
Reputation: 271175
Let's expand the right hand side of the illegal line step by step. First, we start with
BoardItemsHolderRepository<ConstructHolder, Construct>
This is a DataRepository<IList<THolder>>
, so the above is a kind of:
DataRepository<IList<ConstructHolder>>
which in turn is IDataGetRepository<T>
, so the above is a kind of:
IDataGetRepository<IList<ConstructHolder>>
IDataGetRepository<T>
is covariant on T
. Recall exactly what this means: If U
is a subtype of T
, then IDataGetRepository<U>
is a subtype of IDataGetRepository<T>
. For example, IDataGetRepository<Cat>
is a subtype of IDataGetRepository<Animal>
, and so an instance of the former type can be assigned to a variable of the latter type.
However, IDataGetRepository<IList<ConstructHolder>>
is not a subtype of IDataGetRepository<IList<IBoardItemHolder<Construct>>>
and so cannot be assigned to it. Why? Because IList<ConstructHolder>
is not a subtype of IList<IBoardItemHolder<Construct>>
! IList<T>
is invariant on T
!
So what you are trying to do violates type safety, according to the type-checker. Maybe try using a IEnumerable
rather than IList
?
Upvotes: 2