Dan*_*ely 11 c# generics .net-3.5
此代码生成两个编译时错误:
private void DoSomething()
{
List<List<Foo>> myFoos = GetFoos();
UseFoos(myFoos);
}
private void UseFoos(IEnumerable<IEnumerable<Foo>>)
{
}
Run Code Online (Sandbox Code Playgroud)
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
它失败的类型的内部组件有什么不同?
Jon*_*eet 19
编辑:我刚刚意识到我还没有真正回答如何解决限制的问题.幸运的是,这很容易:
UseFoos(myFoos.Cast<IEnumerable<Foo>>());
Run Code Online (Sandbox Code Playgroud)
该代码UseFoos
在C#4下编译得很好(当你给出参数名称时),它引入了接口和委托的通用协方差和逆变.
作为一个更简单的例子,这适用于C#4,但不适用于C#3:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
Run Code Online (Sandbox Code Playgroud)
请注意,即使在C#4中,类也不是不变的,所以这不起作用:
// This won't work
List<string> strings = new List<string>();
List<object> objects = strings;
Run Code Online (Sandbox Code Playgroud)
......甚至对于接口,只有在安全的情况下才支持它:
// This won't work either
IList<string> strings = new List<string>();
IList<object> objects = strings;
Run Code Online (Sandbox Code Playgroud)
接口(或委托)必须声明类型参数本身的方差,所以如果你查看.NET 4 文档,IEnumerable<T>
你会看到它被声明为
public interface IEnumerable<out T>
Run Code Online (Sandbox Code Playgroud)
在哪里out
宣布协方差T
.
埃里克利珀有很多在他的博客类别详细了解此协方差和逆变.