协方差和协方差-调用保证的基类行为的机制不同吗? [英] Covariance and Contravariance - Just different mechanisms for invoking guaranteed base class behavior?

查看:123
本文介绍了协方差和协方差-调用保证的基类行为的机制不同吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难理解这两个概念。但我认为在经过许多视频和质量检查后,我将其提炼为最简单的形式:



协变-假设可以

Contravariant -假设您可以像对待基本类型一样对待子类型。



假设以下三个类别:

 动物类别
{
void Live(动物)
{
//出生!
}

void Die(动物)
{
//已死!
}

}

类别猫:动物
{

}

类别狗:动物
{

}



协变量



任何动物都可以做动物做的事情。

假设一个子类型可以做

  Animal anAnimal = new Cat();  


anAnimal.Live();
anAnimal.Die();

动物anotherAnimal = new Dog();
anotherAnimal.Live();
anotherAnimal.Die();



变量



您可以做的所有事情一种动物,您可以做任何任何动物。

假定您可以像对待基类一样对待亚型

  Action< Animal> kill = KillTheAnimal; 

Cat aCat = new Cat();
KillTheCat(kill,aCat);

Dog = new Dog();
KillTheDog(kill,aDog);

KillTheCat(ActionCataction,Cat aCat)
{
action(aCat);
}

KillTheDog(Action&Dog&action; Dog aDog)
{
action(aDog);
}

void KillTheAnimal(Animal anAnimal)
{
anAnimal.Die();
}

这是正确的吗?似乎到了一天结束时,协方差和逆方差允许您做的只是简单地使用您自然期望的行为,即,动物的每个 type 类型都具有所有 animal 特征,或更笼统地说-所有子类型都实现其基本类型的所有功能。似乎只是为了让表象变得明显-它们只是支持不同的机制,这些机制允许您以不同的方式获得该继承的行为-一种从子类型转换为基本类型(协方差),另一种从基本类型转换为子类型类型(Contravariance),但从根本上讲,它们两者都只允许调用基类的行为。



例如,在上述情况下,您只是考虑到 Cat Dog Animal Dog 子类型的事实c $ c>都有方法 Live Die -它们很自然地从基类<$ c继承$ c>动物。



在两种情况下(协方差和逆方差),我们都允许调用一般行为,因为我们已经做出了保证确保行为被调用的目标是从特定的基类继承的。



对于协方差,我们暗含只需将子类型转换为其基本类型并调用基本类型行为(基本类型行为是否被子类型覆盖都没关系……要点是,我们知道它存在)。 / p>

对于Contravariance ,我们采用一个子类型并将其传递给一个函数,我们知道该函数仅会调用基本类型的行为(因为基本类型是形式参数类型),因此我们可以安全地将基本类型转换为子类型。

解决方案

< blockquote>

我很难理解这两个概念。


是的。很多人都这样做。


但是我认为经过许多视频和质量检查之后,我将其提炼为最简单的形式:


您还没有。


协方差表示子


否。这就是Liskov替换原理。


Contravariance意味着您可以像对待基本类型一样对待子类型。

p>

否。



协方差和逆方差的真正提炼是:




  • 协变转换保留了另一个转换的方向。


  • 协变转换会反转另一个转换的方向。




可转换为 Animal IEnumerable< Dog> 可转换为 IEnumerable< Animal>
方向保持不变,因此 IEnumerable< T> 是协变的。 IComparable< Animal> 可转换为 IComparable< Dog> ,这会反转转换的方向,因此是互变的


我在数学上理解协方差的含义,所以我猜在compsci中也是一样。


要明确一点:数学家使用方差来表示一堆不同的东西。数学和计算机科学的共同含义是范畴理论定义。


在C#中,问题仅在于位置和方式支持这两种类型的关系吗?


从数学上讲,方差告诉您关系是通过映射保留还是逆转。如果我们有映射 T-> IEnumerable< T> 并且关系可通过身份或引用转换转换为,那么在C#中,如果X与Y相关,则 IE< X> IE< Y> 有关。因此,映射关系被认为是协变的。


这些功能通过支持它们试图实现什么?


人们经常要求我有一种方法可以采集一系列动物,而我手中还有一系列乌龟;为什么我必须将序列复制到新序列才能使用该方法?这是一个合理的要求,我们经常得到它,而在LINQ使序列操作变得更容易之后,我们得到了更多的东西。这是一项普遍有用的功能,我们可以以合理的成本实施,因此我们将其实施。


I'm having a struggle understanding these two concepts. But I think after many videos and SO QA's, I have it distilled down to its simplest form:

Covariant - Assumes a sub-type can do what its base-type does.
Contravariant - Assumes you can treat a sub-type the same way you would treat its base-type.

Supposing these three classes:

class Animal
{
    void Live(Animal animal)
    {
        //born!
    }

    void Die(Animal animal)
    {
        //dead!
    }

}

class Cat : Animal
{

}

class Dog : Animal
{

}

Covariant

Any animal can do what animals do.
Assumes a sub-type can do what its base-type does.

Animal anAnimal = new Cat();
anAnimal.Live();
anAnimal.Die();

Animal anotherAnimal = new Dog();
anotherAnimal.Live();
anotherAnimal.Die();

Contravariant

Anything you can do to an animal, you can do to any animal.
Assumes you can treat a sub-type the same way you would treat its base-type.

Action<Animal> kill = KillTheAnimal;

Cat aCat = new Cat();
KillTheCat(kill, aCat);

Dog = new Dog();
KillTheDog(kill, aDog);

KillTheCat(Action<Cat> action, Cat aCat)
{  
    action(aCat);  
}

KillTheDog(Action<Dog> action, Dog aDog)
{  
    action(aDog);  
}

void KillTheAnimal(Animal anAnimal)
{
    anAnimal.Die();
}

Is this correct? It seems like at the end of the day, what covariance and contravariance allow you to do is simply use behavior you would naturally expect, i.e. every type of animal has all animal characteristics, or more generally - all sub-types implement all features of their base-type. Seems like it's just allowing for the obvious - they just support different mechanisms that allow you to get at that inherited behavior in different ways - one converts from sub-type to base-type (Covariance) and the other converts from base-type to sub-type (Contravariance), but at its very core, both are just allowing behavior of the base class to be invoked.

For example in the cases above, you were just allowing for the fact that the Cat and the Dog sub-types of Animal both have the methods Live and Die - which they very naturally inherited from their base class Animal.

In both cases - covariance and contravariance - we are allowing for invocation of general behavior that is guaranteed because we have made sure that the target the behavior is being invoked on inherits from a specific base class.

In the case of Covariance, we are implicitly casting a sub-type to its base-type and calling the base-type behavior (doesn't matter if the base-type behavior is overridden by the sub-type...the point is, we know it exists).

In the case of Contravariance, we are taking a sub-type and passing it to a function we know only invokes base-type behavior (because the base-type is the formal parameter type), so we are safe to cast the base-type to a sub-type.

解决方案

I'm having a struggle understanding these two concepts.

Yes you are. Many people do.

But I think after many videos and SO QA's, I have it distilled down to its simplest form:

You have not.

Covariance means that a sub-type can do what its base-type does.

No. That's the Liskov Substitution Principle.

Contravariance means you can treat a sub-type the same way you would treat its base-type.

No. That's just re-stating what you said for covariance.

The real distillation of covariance and contravariance is:

  • A covariant conversion preserves the direction of another conversion.

  • A contravariant conversion reverses the direction of another conversion.

Dog is convertible to Animal. IEnumerable<Dog> is convertible to IEnumerable<Animal>. The direction is preserved, so IEnumerable<T> is covariant. IComparable<Animal> is convertible to IComparable<Dog>, which reverses the direction of the conversion, so it is contravariant.

I understand mathematically what covariance means, and so I guess it's the same in compsci.

Just to be clear: mathematicians use "variance" to mean a bunch of different things. The meaning that is common to mathematics and computer science is the category theory definition.

In C# it's just a matter of where and in what ways these two types of relationships are supported?

Mathematically, variance tells you about whether a relation is preserved or reversed by a mapping. If we have the mapping T --> IEnumerable<T> and the relation "is convertible to via identity or reference conversion" then it is the case that in C#, if X relates to Y then IE<X> relates to IE<Y>. The mapping is therefore said to be covariant with respect to the relation.

what is it that these features are trying to accomplish by supporting them?

People frequently requested "I have a method that takes a sequence of animals and I have a sequence of turtles in hand; why do I have to copy the sequence to a new sequence to use the method?" That's a reasonable request, we got it frequently, and we got it a lot more frequently after LINQ made it easier to work with sequences. It's a generally useful feature that we could implement at a reasonable cost, so we implemented it.

这篇关于协方差和协方差-调用保证的基类行为的机制不同吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆