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?
In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.
Covariance and contravariance are terms that refer to the ability to use a more derived type (more specific) or a less derived type (less specific) than originally specified. Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types.
Covariance allows assigning an instance to a variable whose type is one of the instance's generic type; i.e. supertype. Contravariance allows assigning an instance to a variable whose type is one of the instance's derived type; i.e. subtype.
This is mainly useful when using already defined standard interfaces. Covariance means that you can use IEnumerable<string> in place where IEnumerable<object> is expected. Contravariance allows you to pass IComparable<object> as an argument of a method taking IComparable<string> . So far, so good.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With