Domanda

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>>
{
}
È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top