I catched this typical compilation error:
Invalid variance: The type parameter 'K' must be covariantly valid on 'ConsoleApplication3.IQuery'. 'K' is contravariant.
I am familiar with the basics of Covariance and Contravariance in C#, but I still can't get why it is wrong:
interface IQuery<in D>
{
}
interface IDct<in K>
{
}
// error here ↓
interface IDctQuery<in K> : IQuery<IDct<K>>
{
}
Please, explain me
UPD
It is interesting that this code is completely valid:
interface IQuery<out D>
{
}
interface IDct<out K>
{
}
interface IDctQuery<out K> : IQuery<IDct<K>>
{
}
What is happening is that by using a contravariant type as a type parameter of another contravariat type, that reverses the direction of the type parameter K. Sounds confusing, but this works fine:
interface IDctQuery<in K> : IQuery<K>
{
}
because K is contravariant in IDctQuery
and IQuery
. But once you add IDct
as a type parameter, the requirement on K is now to be covariant. So you need to change to
interface IDctQuery<out K> : IQuery<IDct<K>>
{
}
Lets say you have two classes, Dog
and Animal
. A Dog
is an Animal
and a covariant interface preserves this relationship. So IEnumerable<Dog>
can be assigned to an IEnumerable<Animal>
.
A contravariant interface reverses this relationship. So an IQuery<Animal>
can be assigned to an IQuery<Dog>
and an IDct<Animal>
can be assigned to an IDct<Dog>
.
Your interface declaration:
interface IDctQuery<in K> : IQuery<IDct<K>>
{
}
says that an IDctQuery<Animal>
can be assigned to an IDctQuery<Dog>
from that it follows that IQuery<IDct<Animal>>
can be assigned to IQuery<IDct<Dog>>
and because IQuery
is contravariant it means that IDct<Dog>
can be assigned to IDct<Animal>
which is not true because IDict
is contravariant and IDct<Animal>
can be assigned to an IDct<Dog>
but not the other way around.