Fre*_*eek 12 .net c# generics .net-4.0 covariance
以下代码无法编译(使用VS2010),我不明白为什么.编译器应该能够推断出List<TestClass>"兼容"(抱歉缺少一个更好的词)IEnumerable<ITest>,但不知何故它没有.我在这里错过了什么?
interface ITest {
void Test();
}
class TestClass : ITest {
public void Test() {
}
}
class Program {
static void Test(IEnumerable<ITest> tests) {
foreach(var t in tests) {
Console.WriteLine(t);
}
}
static void Main(string[] args) {
var lst = new List<TestClass>();
Test(lst); // fails, why?
Test(lst.Select(t=>t as ITest)); //success
Test(lst.ToArray()); // success
}
}
Run Code Online (Sandbox Code Playgroud)
编译器给出了两个错误:
'ConsoleApplication1.Program.Test(System.Collections.Generic.IEnumerable <ConsoleApplication2.ITest>)'的最佳重载方法匹配有一些无效的参数
参数1:无法从'System.Collections.Generic.List <ConsoleApplication2.TestClass>'转换为'System.Collections.Generic.IEnumerable <ConsoleApplication2.ITest>'
你要做的是所谓的协方差 - 从较窄的类型(TestClass)转换为更宽的类型(ITest).这是你将一直习惯的东西,例如当你从一个浮点数转换为一个双精度时.
不幸的是.Net 3.5及更低版本不支持泛型类中的协方差.
.Net 4.0现在确实支持泛型中的协方差(和逆变),前提是这些泛型类是使用out协变类型和in反变量类型的关键字编译的.IEnumerable在.Net 4.0中定义为协变.如果右键单击该IEnumerable类型并单击"转到定义",您将看到:
public interface IEnumerable<out T> : IEnumerable
Run Code Online (Sandbox Code Playgroud)
如果您使用的是VS2010,则需要确保您的项目的目标是.net 4.0.这可以从项目属性更改.右键单击项目,选择属性,转到"应用程序"选项卡,然后检查"目标框架"是否为.Net 4.