C# 4.0 中的泛型变量 [英] Generic Variance in C# 4.0
问题描述
C# 4.0 中的泛型变体的实现方式使得可以无异常地编写以下内容(这就是 C# 3.0 中会发生的情况):
Generic Variance in C# 4.0 has been implemented in such a way that it's possible to write the following without an exception (which is what would happen in C# 3.0):
List<int> intList = new List<int>();
List<object> objectList = intList;
[非功能性示例:参见 Jon Skeet 的回答]
我最近参加了一个会议,在那里 Jon Skeet 对通用方差进行了出色的概述,但我不确定我是否完全理解 - 我理解 in
和 的重要性
当涉及到反差和协方差时,我不知道关键词,但我对幕后发生的事情很好奇.
I recently attended a conference where Jon Skeet gave an excellent overview of Generic Variance, but I'm not sure I'm completely getting it - I understand the significance of the in
and out
key words when it comes to contra and co-variance, but I'm curious to what happens behind the scenes.
执行这段代码时,CLR 看到了什么? 是将 List
隐式转换为 List
还是是不是简单地内置了我们现在可以在派生类型和父类型之间进行转换?
What does the CLR see when this code is executed? Is it implicitly converting the List<int>
to List<object>
or is it simply built in that we can now convert between derived types to parent types?
出于兴趣,为什么没有在以前的版本中引入这一点,主要好处是什么 - 即现实世界的使用?
有关此帖子的更多信息 用于通用方差(但问题非常过时,正在寻找真实的最新信息)
More info on this post for Generic Variance (but question is extremely outdated, looking for real, up-to-date information)
推荐答案
不,您的示例不起作用,原因有以下三个:
No, your example wouldn't work for three reasons:
- 类(例如
List
)是不变的;只有委托和接口是变体 - 要使方差起作用,接口必须仅在一个方向上使用类型参数(in 表示逆变,out 表示协方差)
- 不支持值类型作为变量的类型参数 - 因此没有从
IEnumerable
到IEnumerable
的转换,例如
- Classes (such as
List<T>
) are invariant; only delegates and interfaces are variant - For variance to work, the interface has to only use the type parameter in one direction (in for contravariance, out for covariance)
- Value types aren't supported as type arguments for variance - so there's no converstion from
IEnumerable<int>
toIEnumerable<object>
for example
(代码在 C# 3.0 和 4.0 中都无法编译 - 也不例外.)
(The code fails to compile in both C# 3.0 and 4.0 - there's no exception.)
所以这会工作:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
CLR 只使用引用,不变 - 没有创建新对象.所以如果你调用 objects.GetType()
你仍然会得到 List
.
The CLR just uses the reference, unchanged - no new objects are created. So if you called objects.GetType()
you'd still get List<string>
.
我相信它没有更早被引入,因为语言设计者仍然需要弄清楚如何公开它的细节——它从 v2 开始就在 CLR 中.
I believe it wasn't introduced earlier because the language designers still had to work out the details of how to expose it - it's been in the CLR since v2.
好处与您希望能够将一种类型用作另一种类型的其他时候相同.使用我上周六使用的相同示例,如果您有一些东西实现了 IComparer
来按区域比较形状,那么您不能使用它来对 List< 进行排序真是太疯狂了;Circle>
- 如果它可以比较任何两个形状,它当然可以比较任何两个圆.从 C# 4 开始,将存在从 IComparer
到 IComparer
的逆变转换,因此您可以调用 circles.Sort(areaComparer)代码>.
The benefits are the same as other times where you want to be able to use one type as another. To use the same example I used last Saturday, if you've got something implements IComparer<Shape>
to compare shapes by area, it's crazy that you can't use that to sort a List<Circle>
- if it can compare any two shapes, it can certainly compare any two circles. As of C# 4, there'd be a contravariant conversion from IComparer<Shape>
to IComparer<Circle>
so you could call circles.Sort(areaComparer)
.
这篇关于C# 4.0 中的泛型变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!