2011-07-16 71 views
16

考慮代碼片段。通用協方差和反變量

IList<String> obj=new List<string>(); 
IEnumerable<Object> obj1 = obj; 

但如果我寫ICollection<Object> obj2 = obj;它拋出我一個編譯時錯誤。

不能將類型'System.Collections.Generic.IList<string>'隱式轉換爲'System.Collections.Generic.ICollection<object>'。

爲什麼,因爲List<T>同時實現IEnumerable<T>ICollection<T>這種行爲,也IList<T>被定義爲

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable 
{ 
    T this[int index] { get; set; } 
    int IndexOf(T item); 
    void Insert(int index, T item); 
    void RemoveAt(int index); 
} 

回答

20

ICollection<T>的類型參數不是協變,而IEnumerable<T>是。如果你看他們的聲明(ICollection,IEnumerable),你可以看到IEnumerable<T>使用關鍵字outT,而ICollection<T>沒有。

這是有道理的,如果你仔細想想,因爲(粗略地講)協方差是安全的,當該接口將只用於閱讀對象(因而out關鍵字)。 IEnumerable<T>明顯符合該標準,而ICollection<T>完全相反。

至於什麼可能出問題(使用你的例子)的例子:

IList<String> obj = new List<string>(); // Legal, of course 
ICollection<Object> obj1 = obj;   // Illegal, but let's see what happens 
obj1.Add(new NonStringObject());  // That's not a string being stored in a List<string> 

記住:協方差是不一樣的繼承。僅僅因爲兩個類或接口共享一個繼承關係並不意味着它們的類型參數具有相同的方差特性。

+0

@ dlev.Could you please please more more.I'numerable'IEnumerable 'covariant and'ICollection 'does not。 –

+0

@Ashely剛剛更新了我的答案與該信息。 – dlev

4

這裏的關鍵是該集合是否可修改。 IEnumerable<T>只讀集合T s,而ICollection<T>支持Add。可修改集合不能協變的,因爲:

IList<String> obj = new List<String>(); 
ICollection<Object> obj1 = obj; 
obj1.Add(new Elephant()); 

這類型檢查,因爲(大概)ElephantObject子類。但現在obj,這是一個List<string>有一個Elephant作爲其最後一個元素,這顯然是一件壞事。