Supporting both covariance and contravariance for a single type parameter [duplicate]
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 b开发者_如何转开发oth for different type parameters:
interface IVariant<out R, in A>
So why can't you suport both for a single type parameter?
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.)
It wouldn't work. Consider this (if in out existed):
public class INewList<in out T>
{
public T DoIt(T item);
}
This would be impossible to satisfy because people expecting an INewList<T> would be compatible with interfaces with both narrower and wider types.
Consider INewList<Feline>:
If in/out both were possible, this interface would be equivalent to INewList<Animal> but this would be invalid for in positions because it would allow you to widen to type argument:
... DoIt(Animal item)
Which won't work because that would mean you could pass in a new Dog() instance where a Feline were expected from the original interface.
Similarly in reverse on the out positions because it would allow:
Puma DoIt(...)
Which would be invalid because the original interface could pass back any feline, not necessarily a Puma.
加载中,请稍侯......
精彩评论