2016-05-03 5 views
1

私はC# newbie List<Interface> questionを読んでいて、なぜこの最初の例がうまくいくのか理解できますが、2番目の例は理解できません。なぜ最初の良いのですが、2番目のコードがコンパイルに失敗します。ジェネリックのリストインターフェイスの実装

まず良いコード:

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を実装します。Foo:IFoo?

答えて

4

IZar<TFoo>co-variantではないためです。あなたはそのようなインターフェイスをダウンキャストすることはできません。

あなたはoutを使用することにより、IZar<TFoo>共同バリアントを行う必要があります。

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

あなたがaddメソッドを作成するときに問題が明確になる:あなたがインターフェイスを使用する場合は

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

を、あなたは実際にタイプがFooまたはBarIFooが追加される可能性があります。 IFooFooまたはBarのいずれかになる可能性があるため、返品には問題はありません。参照してください、継承の問題はありません:

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

関連する問題