6

“协变”和“逆变”这两个概念的含义是什么?

给定 2 个类AnimalElephant(从Animal继承),我的理解是,如果您尝试将 Elephant 放入 Animals 数组中,您会遇到运行时错误,这是因为 Elephant 是“更大”(更多具体)比动物。但是,您能否将 Animal 放入 Elephant 数组中,看看 Elephant 是如何保证包含 Animal 属性的?

4

4 回答 4

10

你倒过来了。您可以将 Elephant 添加到 Animal 数组中,因为它Animal,并且保证具有 Animal 所需的所有方法。您不能将 Animal 添加到 Elephant 数组,因为它没有Elephant所需的所有方法。

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

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

另外,您说 Elephant 类型“更大”,事实并非如此。类型 Animal 是“更大”的,因为它包括更具体的类型,例如 Elephant、Giraffe 和 Lion。

于 2008-11-07T15:31:34.290 回答
2

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

http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx

于 2008-11-07T15:31:28.597 回答
0

您应该尝试阅读使用 Visual Studio 2010 介绍 .NET 4.0的第 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
{
}
于 2012-10-17T00:43:22.720 回答
-1

在此处输入图像描述

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;
于 2018-11-14T17:02:00.490 回答