-
18-09-2019 - |
题
泛差异C#4.0在已实施这样一种方式,它可以编写以下,无一例外(这是什么会发生在C#3.0):
List<int> intList = new List<int>();
List<object> objectList = intList;
[例如非功能:看见乔恩的飞碟的答案]
我最近参加了一个会议在乔恩的飞碟给了一个极好的概述,通用的差异,但是我不确定我完全得到它-我理解的意义 in
和 out
关键词,当它涉及到禁忌和共差异,但我很好奇会发生什么在幕后。
什么CLR看到,当执行该代码? 它是隐含地转换 List<int>
要 List<object>
或者它仅仅是建立在我们现在可以转换之间的源类型父母的类型?
出兴趣,为什么不是这样介绍了在以前版本的,什么是主要的利益-即真正的世界的使用情况?
更多信息在这 后 为通用的方差(但问题是极其过时的,在寻找真正的、最新的信息)
解决方案
不,你不会的工作有三个原因:
- 课程(例如
List<T>
)是固定;只有各国代表和接口都是变异 - 对差异的工作,该接口拥有仅使用的类型参数的一个方向(在于逆变,出于协)
- 值的类型不支持的类型参数差异,因此没有转换从
IEnumerable<int>
要IEnumerable<object>
例如
(代码无法编制在两个C#3.0和4.0-有没有例外。)
所以这 会 工作:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
CLR只是使用的基准,维持不变-没有新的目的是创建。所以如果你被称为 objects.GetType()
你还是会得到 List<string>
.
我相信这不是前面介绍,因为语言设计师仍然不得不工作的细节如何让它-它已经在CLR由于v2。
本利益是相同的其他时间在这里你想要能够使用一种类型的作为另一个。使用同样的例子,我用最后一个星期六,如果你已经得到的东西实现了 IComparer<Shape>
比较形状的地区,这太疯狂了,你不能使用,进行排序 List<Circle>
-如果可以比较的任何两个形状,这当然可以比较的任何两个圈子。作为C#4,还会有一个逆变的转换 IComparer<Shape>
要 IComparer<Circle>
所以你可以叫 circles.Sort(areaComparer)
.
其他提示
一个几个额外的想法。
什么是CLR看到,当执行该代码
随着乔恩和其他人正确地指出,我们不是做在类方差,只有接口和委托。因此,在你的榜样,在CLR什么也看不到;代码不编译。如果你强迫它通过插入足够的强制类型转换来编译,它崩溃在一个坏的转换异常运行。
现在,它仍然是一个合理的问题要问方差如何在幕后工作时,它的工作。答案是:我们是制约此引用类型变量是参数化接口和委托类型的理由是,这样的没有的发生在幕后。当你说
object x = "hello";
会发生什么幕后是参照串刺入类型的对象的的可变无需修改。组成一个字符串的引用该位是法律位是一个对象的引用,所以没有什么需要就发生在这里。在CLR简单地停止那些比特为指的是字符串的思维和开始思考它们作为参考的对象。
当你说:
IEnumerator<string> e1 = whatever;
IEnumerator<object> e2 = e1;
同样的事情。什么都没发生。使一个裁判的字符串枚举的比特是相同的,使一个对象枚举的引用的位。有几分当你做一个演员,说,进场更神奇的:
IEnumerator<string> e1 = whatever;
IEnumerator<object> e2 = (IEnumerator<object>)(object)e1;
现在的CLR必须产生一个检查,实际上E1确实实现该接口,并且该检查必须是智能关于识别方差。
但是,我们可以用变异的接口是只是空操作转换脱身的原因是的,因为的定期分配兼容性是这样的。你打算使用E2呢?
object z = e2.Current;
这返回是一个字符串一个参考比特。我们已经确定了那些与不改变的对象兼容。
为什么没有这种早些时候推出?我们有一些其他的功能做的,在有限的预算。
什么是原则的好处?从串的序列转化至对象的“只是工作”序列。
出于兴趣,为什么不这样 在以前的版本引入
.NET的第一版本(1.x中)没有泛型可言,因此通用方差太远。
应当注意的是,在.NET的所有版本,有阵列协方差。不幸的是,这是不安全的协方差:
Apple[] apples = new [] { apple1, apple2 };
Fruit[] fruit = apples;
fruit[1] = new Orange(); // Oh snap! Runtime exception! Can't store an orange in an array of apples!
在C#4的共和反方差是安全的,并且防止了这个问题。
什么是主要的好处 - 即实 世界的用法?
在代码中很多时候,你是调用API预计碱(如IEnumerable<Base>
)的放大类型,但是你所得到的是派生的(例如IEnumerable<Derived>
)的放大型。
在C#2和C#3,你需要手动转换为IEnumerable<Base>
,即使它应该“只是工作”。 CO-和反方差使得它“只是工作”。