2016-05-03 43 views
1

我一直在讀C# newbie List<Interface> question和可以理解爲什麼第一個例子中的作品,而不是第二。爲什麼第一個好,但第二個代碼沒有編譯。列表實現一個接口

首先是好碼:

interface IFoo {} 
class Foo : IFoo { } 
class Bar : IFoo { } 

     var list = new List<IFoo>(); 
     list.Add(new Foo()); 
     list.Add(new Bar()); 

現在對於它引入了泛型

interface IZar<TFoo> where TFoo : IFoo { } 
class ZarFoo : IZar<Foo> { } 
class ZarBar : IZar<Bar> { } 

     var list2 = new List<IZar<IFoo>>(); 
     list2.Add(new ZarFoo()); 
     list2.Add(new ZarBar()); 

的代碼是不能編譯,因爲ZarFoo不能轉換爲IZAR時,想必應該能夠爲它實現了IZar Foo:IFoo?

回答

4

因爲IZar<TFoo>co-variant。就像那樣,你不能倒下界面。

你必須要IZar<TFoo>共變,通過使用out

interface IZar<out TFoo> where TFoo : IFoo { } 

當你創建一個附加方法的問題變得清晰:

interface IZar<TFoo> where TFoo : IFoo 
{ 
    void Add(TFoo foo); 
} 
class ZarFoo : IZar<Foo> 
{ 
    public void Add(Foo foo) 
    { } 
} 
class ZarBar : IZar<Bar> 
{ 
    public void Add(Bar foo) 
    { } 
} 

,如果您使用的接口,你最終可能會增加一個IFoo,其中實際類型是FooBar。返回沒有這個問題,因爲IFoo可以是FooBar。看,沒有遺產問題:

interface IZar<out TFoo> where TFoo : IFoo 
{ 
    TFoo GetOne(); 
} 
class ZarFoo : IZar<Foo> 
{ 
    public Foo GetOne() 
    { return new Foo(); } 
} 
class ZarBar : IZar<Bar> 
{ 
    public Bar GetOne() 
    { return new Bar(); } 
} 
+0

很好的例子,並說明問題很好,謝謝花時間解釋。 MSDN鏈接在多個頁面上非常冗長!對於簡短版本 - https://msdn.microsoft.com/en-us/library/dd997386.aspx – user3791372