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 = ActionObject
和o = RetrieveString
得到了相同的结果。(我测试了Mono)。
- 那么,为什么作者用
new
来解释协方差/逆变? 协方差/逆变思想背后的理论是什么?它只是一个描述
object x = Everything inherit from object
的花哨名字吗?这个奇怪的名字是怎么来的?它的用途是什么?我有一本书是这样解释逆变/协方差的…
这不是方差的一个很好的解释。完全不清楚到底什么叫做"协方差"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();