2011-02-02 63 views
0

大象:動物....IList <T> vs IEnumerable <T>:爲什麼此作業無效?

IList<Elephant> elephants = new List<Elephant>(); 
IEnumerable<Animal> animalList = elephants; 

能正常工作,但..

IList<Elephant> elephants = new List<Elephant>(); 
IList<Animal> animalList = elephants; 

拋出一個錯誤。這是爲什麼?

+0

[關於C#協方差的問題](http:// stackoverflow。com/questions/4034495/question-about-c-sharp-covariance) – nawfal 2013-06-10 16:52:59

回答

11

如果

IList<Elephant> elephants = new List<Elephant>(); 
IList<Animal> animalList = elephants; 

是可能的,你可以再做到這一點

animalList.Add(new Animal()); 

animalList真的是相同的referrent作爲elephants參考。並且因爲elephantsIList<Elephant>,您會嘗試將Animal的實例添加到只能包含Elephant實例的集合中。

IEnumerable<T>可能的原因是IEnumerable<T>covariant在類型參數T。這是因爲T只出現在接口IEnumerable<T>的「出」位置。由於您只是從IEnumerable<T>消耗T的實例,因此將IEnumerable<Derived>的實例分配給類型爲IEnumerable<Base>的變量是安全的。任何來自IEnumerable<Derived>的是Base,這就是爲什麼實施IEnumerable<Derived>的東西可以安全地用作IEnumerable<Base>。這就是爲什麼將IEnumerable<Elephant>的實例分配給IEnumerable<Animal>類型的變量是安全的。

但是,由於IList<T>在類型參數T中不是協變的,所以你遇到了問題IList<T>。這裏的問題是T出現在接口IList<T>的「in」位置。因此,如果您可以將IList<Derived>的實例分配給IList<Base>類型的變量,那麼您可以嘗試將Base的實例粘貼到IList<Base>中,這實際上試圖將Base的實例粘貼到IList<Derived>的實例中,這顯然不安全。這正是我們剛剛遇到的IList<Elephant>IList<Animal>的問題。

請注意,IList<T>在類型參數T中也不是相反的。這是因爲T出現在接口IList<T>的「出」位置。如果您可以將IList<Base>的實例分配給IList<Derived>類型的變量,那麼您可以嘗試從IList<Derived>中獲取Derived的實例,該實例將嘗試從IList<Base>的實例中獲取實例Derived,這顯然是荒謬的。

+0

還要注意`Derived []`可以用作Base [],插入Derived會引發異常。這是因爲.NET繼承了圍繞數組差異的破碎的Java規則。 – porges 2011-02-02 04:45:19

1

這稱爲協方差逆變函數

我不會詳談,但你可以read about it

相關問題