c#中的协方差/逆变

本文关键字:逆变 方差 | 更新日期: 2023-09-27 18:03:05

我有一本书是这样解释逆变/协方差的:

  • 一个委托可以有比它的方法目标更具体的参数类型。这被称为逆变
  • 委托的返回类型可以比它的目标方法的返回类型更不具体。这被称为协方差

这是一个例子。

using System;
delegate void StringAction(string s);
delegate object ObjectRetriever();
class Test
{
    static void Main()
    {
        StringAction sa = new StringAction(ActionObject);
        sa("hello");
        ObjectRetriever o = new ObjectRetriever(RetrieveString);
        object result = o();
        Console.WriteLine(result);
    }

    static string RetrieveString() {return "hello";}
    static void ActionObject(object o)
    {
        Console.WriteLine(o);
    }
}

我认为为了使用协方差/逆变,需要使用new,如示例所示,但我似乎用sa = ActionObjecto = RetrieveString得到了相同的结果。(我测试了Mono)。

  • 那么,为什么作者用new来解释协方差/逆变?
  • 协方差/逆变思想背后的理论是什么?它只是一个描述object x = Everything inherit from object的花哨名字吗?这个奇怪的名字是怎么来的?它的用途是什么?

c#中的协方差/逆变

我有一本书是这样解释逆变/协方差的…

这不是方差的一个很好的解释。完全不清楚到底什么叫做"协方差"answers"逆变变"。

实际上是变体的东西从未被提及。逆变的是从一个类型到一个带有该类型参数的委托的映射。逆变是映射关系的一个属性。

试着读一下,看看你是否能更好地理解它:

http://blogs.msdn.com/b/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx

我认为为了使用协方差/逆变,需要使用new,如示例所示,但我似乎得到了相同的结果…

从c# 2.0开始,你可以说"d = M"或"d = new d (M)"——编译器只是将它们识别为相同内容的两种不同的书写方式。

为什么作者用new来解释协方差/逆变?

我不知道。

协方差/逆变思想背后的理论是什么?

理论是,如果你有一个排序关系——也就是说,X大于Y,如果X X = (Y) Y是合法的——并且你有一个映射保持排序关系,那么这个映射是协变的。如果颠倒了的排序关系,则是逆变

例如,假设Animal是一个比Giraffe大的类型。所以你可以把长颈鹿类型的对象赋值给动物类型的变量。动物>长颈鹿

现在做一个映射,从一个类型T到一个方法m -需要a-T,到一个委托类型d -需要a-T。

你可以将一个取一个动物的方法m分配给一个取一个长颈鹿的变量d。D(长颈鹿)> M(动物)但是动物>长颈鹿。关系反向;映射逆变

它只是一个花哨的名字描述对象x =一切继承自对象?

。它与相关,因为object类型比几乎所有其他类型都要大。但真正的变体是映射,它保留或反转大小关系。

试着读一下,看看是否有帮助。

http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx

这个奇怪的名字是从哪里来的?

范畴理论。

在我所见过的c#中描述协方差/逆变性的最好的信息是Eric Lippert的一系列博客文章。请参阅从列表底部开始,由11个部分组成的系列。

有时读起来有点困难。但它解释了你一开始可能会问的所有问题。:)

它是在实际c# 4.0实现之前编写的,所以对语法的一些讨论已经过时了,但其他一切似乎都按照描述实现了。

这里有一篇很棒的wiki文章:这里

这更多的是一个方向漏斗倒和设置漏斗的宽度在一个适当的水平…

我不知道你第一个问题是什么意思。

第二个问题可以通过建议查看类型转换来回答。逆变性是允许具有扩展类B的类A存储为类B。

抗变性

class A {
}
class B : public A {
}
B obj = new A();

协方差允许类B扩展类A,但存储为类A。

协方差

class A {
}
class B : public A {
}
A obj = new B();