//covariant operation
Animal someAnimal = new Giraffe();
//assume returns Mammal, also covariant operation
someAnimal = Mammal.GetSomeMammal();
这里的返回操作是协变的,因为我们保留了Animal比Mammal或Giraffe大的尺寸。需要注意的是,大多数返回操作都是协变的,而逆变操作则没有意义。
//if return operations were contravariant
//the following would be illegal
//as Mammal would need to be stored in something
//equal to or less derived than Mammal
//which would mean that Animal is now less than or equal than Mammal
//therefore reversing the relationship
Animal someAnimal = Mammal.GetSomeMammal();
当然,对于大多数开发者来说,这段代码毫无意义。
我的困惑在于逆变参数。如果你有一个方法,例如
bool Compare(Mammal mammal1, Mammal mammal2);
我一直认为输入参数总是强制反变行为。因此,如果类型用作输入参数,则其行为应该是反变的。
然而,以下代码有什么区别
Mammal mammal1 = new Giraffe(); //covariant
Mammal mammal2 = new Dolphin(); //covariant
Compare(mammal1, mammal2); //covariant or contravariant?
//or
Compare(new Giraffe(), new Dolphin()); //covariant or contravariant?
同样的道理,你不能做这样的事情,也不能做
//not valid
Mammal mammal1 = new Animal();
//not valid
Compare(new Animal(), new Dolphin());
我想问的是,什么使得方法参数传递成为一个反变换。抱歉发帖很长,也许我对此的理解不正确。
编辑:根据下面的交谈,我理解例如使用委托层可以清楚地显示反变性。考虑以下示例。
//legal, covariance
Mammal someMammal = new Mammal();
Animal someAnimal = someMammal;
// legal in C# 4.0, covariance (because defined in Interface)
IEnumerable<Mammal> mammalList = Enumerable.Empty<Mammal>();
IEnumerable<Animal> animalList = mammalList;
//because of this, one would assume
//that the following line is legal as well
void ProcessMammal(Mammal someMammal);
Action<Mammal> processMethod = ProcessMammal;
Action<Animal> someAction = processMethod;
当然,这是非法的,因为有人可以将任何动物传递给someAction,而ProcessMammal只期望任何是哺乳动物或更具体(小于哺乳动物)的东西。这就是为什么someAction必须只是Action或任何更具体的东西(Action)。
然而,这引入了一个代理层,是否有必要在中间使用代理才能进行逆变投影?如果我们将Process定义为一个接口,我们将声明参数作为逆变类型,只是因为我们不希望某人能够像上面使用委托那样做?
public interface IProcess<out T>
{
void Process(T val);
}