2010-05-20 51 views
12

下面的代码无法编译(使用VS2010),我不明白为什么。编译器应该能够推断List<TestClass>IEnumerable<ITest>是“兼容的”(对不起,因为缺少一个更好的词),但不知何故它没有。我在这里错过了什么?C#编译器无法识别一个类正在实现一个接口


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 
    } 
} 

编译器给出两个错误:

  1. 关于“ConsoleApplication1.Program.Test(System.Collections.Generic.IEnumerable < ConsoleApplication2最好重载方法匹配.ITest >)'有一些无效论据

  2. 参数1:无法从 'System.Collections.Generic.List <ConsoleApplication2.TestClass>' 转换为 'System.Collections.Generic.IEnumerable <ConsoleApplication2.ITest>'

回答

8

你正在做的事情叫做covariance - 从较窄的类型(TestClass)转换为更宽的类型(ITest)。这是你永远都会用到的东西,例如当你从一个float转换为double时。

不幸的是,.net 3.5及更低版本不支持泛型类中的协方差。

.net 4.0现在确实支持泛型中的协变性(和相反性),前提是这些泛型类使用协变类型的关键字out和对于变型类型的in进行编译。 .Net 4.0中的IEnumerable被定义为协变。如果你对上IEnumerable类型并单击“转到定义”,你会看到这一点:

public interface IEnumerable<out T> : IEnumerable 

如果你正在使用VS2010,你需要确保你的项目的目标是.NET 4.0。这可以从项目属性进行更改。右键单击项目,选择属性,转到“应用程序”选项卡,并检查“目标框架”是否为.Net 4.

MSDN has more information

2

这有可能做与方差(协方差和逆变);看看这个post和Jon Skeet的答案

1

检查项目框架的目标版本。该代码只能在.NET 4中运行。