2008-10-21 124 views
32

這可能是一個古老的問題:爲什麼IEnumerable<T>繼承自IEnumerable爲什麼IEnumerable <T>從IEnumerable繼承?

這是.NET的做法,但它帶來了一些麻煩。每次我寫一個類實現IEumerable<T>,我必須寫兩個GetEnumerator()函數,一個用於IEnumerable<T>,另一個用於IEnumerable

而且,IList<T>不自IList繼承。

我不知道爲什麼IEnumerable<T>的設計在其他的方式。

回答

48

Straight from the horse's mouth(Hejlsberg):

地全部泛型集合接口(如ICollection<T>IList<T>)將從其非一般的同行繼承,使得通用接口實例可以與通用和非均可使用通用代碼。例如,如果能夠將IList<T>傳遞給期望IList的代碼,那將是方便的。

事實證明,唯一的通用接口針對這是可能是IEnumerable<T>,因爲只有IEnumerable<T>是禁忌的變體:在IEnumerable<T>,類型參數T僅用於「輸出」位置(返回值),而不是在「輸入」位置(參數)。 ICollection<T>IList<T>在輸入和輸出位置都使用T,因此這些接口是不變的。 (順便說一句,他們會一直禁忌變種如果T僅在輸入位置使用,但沒有真正的問題在這裏。)

< ...喀嚓...>

所以,要回答你的問題,IEnumerable<T>繼承自IEnumerable,因爲它可以! :-)

+1

這很有趣......我真的很煩惱,`IList `沒有繼承`IList`,但只要你考慮到它的差異,它開始有意義... – 2009-11-29 01:01:04

+1

這太糟糕了微軟從來沒有定義IReadableByIndex和IReadableByIndex (Of T),可以由IList和IList(Of T)繼承。 IReadableByIndex可以被IReadableByIndex(Of T)毫無困難地繼承,只讀索引集合的方差會非常好。 – supercat 2011-01-16 23:06:01

16

IEnumerable的答案是:「因爲它不會影響類型安全性」。

IEnumerable是一個「只讀」接口 - 所以通用形式比非通用形式更具體無關緊要。通過實施兩者,你不會破壞任何東西。 IEnumerator.Current返回object,而IEnumerator<T>.Current返回T - 沒關係,因爲您總是可以合法地轉換爲object,儘管這可能意味着拳擊。

比較這與IList<T>IList - 你可以調用Add(object)IList,而這很可能是針對任何特定IList<T>(比實際IList<object>其他任何東西)無效。

布拉德·艾布拉姆的blogged with Anders' answer大約過這個問題。

2

這樣就可以與不支持泛型的類一起工作。此外,.NET泛型不會讓你像IList < long>那樣執行IList < int>,因此當需要固定的基類或接口時,非泛型接口版本可能非常有用。

+0

這個重要的一點。 IList 不能鑄造到IList 。 – 2008-10-21 14:18:39

3

這是爲了向後兼容。如果你打電話給.Net 1。1函數期望一個香草IEnumerable你可以在你的通用IEnumerable傳遞。

Luckilly通用的IEnumerator從舊式的IEnumerator

我通常實現返回一個枚舉的私有方法,然後通過它的新舊和款式GetEnumerator方法繼承。

private IEnumerator<string> Enumerator() { 
     // ... 
    } 

    public IEnumerator<string> GetEnumerator() { 
     return Enumerator(); 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 
     return Enumerator(); 
    } 
相關問題