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

Class 关于类继承的协方差与逆变,class,inheritance,terminology,covariance,contravariance,Class,Inheritance,Terminology,Covariance,Contravariance,“协方差”和“逆方差”的概念是什么意思 给定两个类,Animal和Elephant(继承自Animal),我的理解是,如果尝试将大象放入一组动物中,会出现运行时错误,这是因为大象比动物“更大”(更具体)。但是你能把一只动物放到大象的数组中,看看大象是如何保证包含动物属性的吗?看看C#4.0中协方差和逆变的概述,看看这是否有帮助: 你把它倒过来了。您可以将大象添加到动物数组中,因为它是一种动物,并且它保证具有动物所需的所有方法。您不能将动物添加到大象数组中,因为它不具备大象所需的所有方法 维基百科

“协方差”和“逆方差”的概念是什么意思


给定两个类,AnimalElephant(继承自Animal),我的理解是,如果尝试将大象放入一组动物中,会出现运行时错误,这是因为大象比动物“更大”(更具体)。但是你能把一只动物放到大象的数组中,看看大象是如何保证包含动物属性的吗?

看看C#4.0中协方差和逆变的概述,看看这是否有帮助:


你把它倒过来了。您可以将大象添加到动物数组中,因为它是一种动物,并且它保证具有动物所需的所有方法。您不能将动物添加到大象数组中,因为它不具备大象所需的所有方法

维基百科关于的文章对此有很好的解释:

在编程语言的类型系统中,一个从类型到类型的运算符是协变的,如果它保持顺序,≤, 类型,将类型从更具体的类型排序为更通用的类型;如果它反转此顺序,则为逆变。如果两者都不适用,则运算符是不变的。这些术语来自范畴理论


还有,你说大象体型更大,但事实并非如此。类型动物“更大”,因为它包括更具体的类型,如大象、长颈鹿和狮子。

你应该试着阅读第45-49页,其中涉及到这个确切的例子。它甚至有一些漂亮的大象照片

主要的一点是,这样做

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

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

public interface IThing<out T> where T : IContent
{
}
公共接口,其中T:IContent
{
}

公共接口输出
{
T Func();
}
公共接口IComeIn
{
无效行为(T-obj);
}
公共类GoOutClass:igoot
{
公共T Func()
{
返回默认值(T);
}
}
公共类ComeInClass:IComeIn
{
公共无效诉讼{}
}
==========================================================
objectobj=null;
//协方差示例[Array+IEnumerable+IEnumerator+IInterface+Func]
对象[]数组=(字符串[])obj;
IEnumerable enumerable=(IEnumerable)obj;
IEnumerator枚举器=(IEnumerator)obj;
IGOUT goOut=(GoOutClass)obj;
Func Func=(Func)obj;
//抵销示例[界面]
IComeIn comeIn=(COMEINCASS)obj;

啊,这是有道理的,那么你会说大象与动物是协变的,而动物与大象是逆变的吗?这取决于你对这些类型做了什么。大象的方法需要返回与动物方法相同或更窄的类型(如果动物方法返回动物,它们可以返回动物或大象)。这将被称为协变。但大象的方法参数需要与动物的方法相同或更宽。这是逆差。有用:
public interface IThing<out T> where T : IContent
{
}
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;