我没有参加2008年的PDC,但是我听说C# 4.0宣布支持泛型协变和逆变。也就是说,List<string>
可以被赋值给List<object>
。这是怎么做到的?
在Jon Skeet的书《C#深度剖析》中,解释了为什么C#泛型不支持协变和逆变。主要是为了编写安全的代码。现在,C# 4.0改变了这一点来支持它们。这会带来混乱吗?
有人知道关于C# 4.0的细节可以给出一些解释吗?
我没有参加2008年的PDC,但是我听说C# 4.0宣布支持泛型协变和逆变。也就是说,List<string>
可以被赋值给List<object>
。这是怎么做到的?
在Jon Skeet的书《C#深度剖析》中,解释了为什么C#泛型不支持协变和逆变。主要是为了编写安全的代码。现在,C# 4.0改变了这一点来支持它们。这会带来混乱吗?
有人知道关于C# 4.0的细节可以给出一些解释吗?
List<Banana>
作为List<Fruit>
(或其他内容)使用的示例仍然不起作用 - 但是还有一些其他情况可以使用。in
(用于逆变)或out
(用于协变)。最明显的例子是IEnumerable<T>
,它只允许从中获取值 - 不允许您添加新值。那将变成IEnumerable<out T>
。这完全不会损害类型安全性,但允许您从声明返回IEnumerable<object>
的方法返回IEnumerable<string>
等。Action<T>
- 它只表示一个接受T
参数的方法。如果能够无缝地转换使用Action<object>
作为Action<string>
,那就太好了 - 任何接受object
参数的方法在使用string
时都没有问题。当然,C#2已经在某种程度上具有委托的协变性和逆变性,但是通过将一个委托类型转换为另一个委托类型(创建新实例)来实现的 - 参见P141-144的例子。C#4将使这更加通用,并且(我相信)将避免为转换创建新实例。(它将是引用转换而不是创建新实例。)List<Banana>
用作IList<Fruit>
"这种说法是正确的吗?如果是这样,那么尽管IList<T>
接口的类型参数没有定义为协变(没有out T
,而只是简单的T
),这是如何实现的呢? - gehho虽然Jon已经覆盖了这个主题,但这里有一些来自Eric Lippert的博客和视频链接。他用例子做得很好。
https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and-contravariance-in-c-part-one/
这些视频:
https://www.youtube.com/watch?v=3MQDrKbzvqU