2010-05-20 36 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中運行。

相關問題