关于类继承的协方差与逆变

时间:2008-11-07 15:26:11

标签: class inheritance terminology covariance contravariance

概念'协方差'和'逆变'是什么意思?

鉴于2个类, Animal Elephant (继承自 Animal ),我的理解是您会遇到运行时错误如果你试图将一只大象放入一系列动物中,这就发生了,因为大象比动物“更大”(更具体)。但是你可以将动物放入大象阵列中,看看大象是如何保证包含动物属性的吗?

4 个答案:

答案 0 :(得分:9)

你倒退了。您可以将Elephant添加到Animal数组中,因为它 Animal,并且它保证拥有Animal所需的所有方法。您无法将Animal添加到Elephant数组中,因为它具有Elephant所需的所有方法。

关于covariance and contravariance的维基百科文章对此有一个很好的解释:

  

在编程语言的类型系统中,从类型到类型的运算符是协变的,如果它保留类型的排序,≤,将类型从更具体的类型排序到更通用的类型;如果它颠倒了这种顺序,它就是逆变的。如果这些都不适用,则运算符是不变的。这些术语来自范畴理论。

另外,你说类型大象是“更大”,事实并非如此。类型动物是“更大”的,因为它包含更具体的类型,如大象,长颈鹿和狮子。

答案 1 :(得分:2)

答案 2 :(得分:0)

你应该尝试阅读Introducing .NET 4.0 With Visual Studio 2010的第45-49页来处理这个确切的例子。它甚至还有一些很好的大象照片。

要取出的主要观点是,

var things = new List<IThing<IContent>> { new ConcreteThing() }

使用:

public class ConcreteThing : IThing<ConcreteContent>
{

}

您需要在接口定义中使用“out”,这将允许设置更具体的表单,但必须保证从IThing中读取的任何内容都是更通用的类型。

public interface IThing<out T> where T : IContent
{
}

答案 3 :(得分:0)

enter image description here

public interface IGoOut<out T>
{
    T Func();
}
public interface IComeIn<in T>
{
    void Action(T obj);
}
public class GoOutClass<T>:IGoOut<T>
{
    public T Func()
    {
        return default(T);
    }
}

public class ComeInClass<T> : IComeIn<T>
{
    public void Action(T obj) {  }
}

==========================================================
object obj = null;
//Covariance Example [Array +  IEnumerable<T> +  IEnumerator<T>  +  IInterface<Out T>  +  Func<T>]
object[] array = (string[]) obj;
IEnumerable<object> enumerable = (IEnumerable<string>) obj;
IEnumerator<object> enumerator = (IEnumerator<string>)obj;
IGoOut<object> goOut = (GoOutClass<string>)obj;
Func<object> func = (Func<string>)obj;


//Contravariance Example[IInterface<in T>]
IComeIn<string> comeIn = (ComeInClass<object>) obj;