此代码生成两个编译时错误:
private void DoSomething()
{
List<List<Foo>> myFoos = GetFoos();
UseFoos(myFoos);
}
private void UseFoos(IEnumerable<IEnumerable<Foo>>)
{
}
The best overloaded method match for 'NameSpace.Class.UseFoos(System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<Foo>>)' has some invalid arguments
和
Argument 1: cannot convert from 'System.Collections.Generic.List<System.Collections.Generic.List<Foo>>' to 'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<Foo>>'
转换为IEnumberable<List<Foo>>
不是问题。如何构建它失败的类型的内部List
组件有什么不同?
答案 0 :(得分:19)
UseFoos(myFoos.Cast<IEnumerable<Foo>>());
在C#4下,该代码编译得很好(当你给UseFoos
参数一个名字时),这为接口和代表引入了通用协方差和逆变。
作为一个更简单的例子,这适用于C#4,但不适用于C#3:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
请注意,即使在C#4中,课程也不是不变的,所以这不会起作用:
// This won't work
List<string> strings = new List<string>();
List<object> objects = strings;
......甚至对于界面,只有在安全的情况下才支持它:
// This won't work either
IList<string> strings = new List<string>();
IList<object> objects = strings;
接口(或委托)必须声明类型参数本身的方差,所以如果你看一下.NET 4 documentation for IEnumerable<T>
,你会看到它被声明为
public interface IEnumerable<out T>
其中out
在T
声明了协方差。
Eric Lippert在他的博客类别covariance and contravariance中有更多关于此事的很多。