开发者

Supporting both covariance and contravariance for a single type parameter [duplicate]

开发者 https://www.devze.com 2023-03-20 09:21 出处:网络
This question already has answers here: Closed 11 years ago. Possible Duplicate: Covariance and Contravariance on the same type argument
This question already has answers here: Closed 11 years ago.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消