Search code examples
c#genericsinterfacecovariancecontravariance

Supporting both covariance and contravariance for a single type parameter


Possible Duplicate:
Covariance and Contravariance on the same type argument

You can declare a generic type parameter as covariant by using the out keyword:

interface ICovariant<out R>

You can declare a generic type parameter as contravariant by using the in keyword:

interface IContravariant<in R>

And you can also support both for different type parameters:

interface IVariant<out R, in A>

So why can't you suport both for a single type parameter?


Solution

  • So why can't you suport both for a single type parameter?

    Keep in mind that an interface can only be covariant in a type parameter if that type parameter is output-safe and an interface can only be contravariant in a type parameter if that type parameter is input-safe.

    The syntax out T says that T is a covariant type parameter.

    The syntax in T says that T is a contravariant type parameter.

    As T is a covariant type parameter, it is by definition input-unsafe.

    As T is a contravariant type parameter, it is by definition output-unsafe.

    Therefore, T is input-unsafe and output-unsafe.

    Consequently, T is prohibited in input positions, and T is prohibited in output positions.

    Therefore, T can not appear in input positions nor in any output positions on any methods specified by the interface.

    Consequently, T can not be used on the interface at all, and is pointless as a type parameter. Consequently, the language designers prohibit you from even including such a useless type marked as both covariant and contravariant on the interface to avoid the ugly

    interface IFoo<in and out T> { }
    Foo<T> : IFoo<T> { }
    

    and then:

    IFoo<Cat> cat = (IFoo<Animal>)new Foo<Dog>();
    

    (If you need to read up on input-safe and output-safe, see 13.1.3.1 of the language specification.)