2008-10-21 21 views
32

Bu eski bir soru olabilir: Neden IEnumerable<T>IEnumerable'dan mi?Neden IEnumerable <T> IEnumerable öğesinden devralınır?

.NET'in işi budur, ancak biraz sorun çıkarır. Bir sınıf yazdığım her zaman IEumerable<T>, iki GetEnumerator() işlevini, IEnumerable<T> için ve diğeri IEnumerable için yazmam gerekiyor.

Ve IList<T>, IList'ten devralmaz.

Neden IEnumerable<T> başka şekilde tasarlandığını bilmiyorum.

cevap

48

Straight from the horse's mouth (Hejlsberg): İdeal

jenerik toplama arayüzleri tüm (örn ICollection<T>, IList<T>) jenerik arayüz örnekleri jenerik ve sivil hem kullanılabilecek şekilde kendi olmayan jenerik benzerlerinden devralırdı genel kod. Örneğin, bir IList<T>'un IList olmasını bekleyen koda geçirilebilmesi uygun olacaktır. Görünen o ki, sadece IEnumerable<T> ters varyantı olduğu

, bu mümkün olan tek genel bir arayüz, IEnumerable<T> olup: IEnumerable<T>, tür parametresi T, sadece "çıkış" pozisyonda kullanılabilir (dönüş değerleri) ve değildir "giriş" pozisyonlarında (parametreler). ICollection<T> ve IList<T> hem giriş hem de çıkış konumlarında T'yi kullanır ve bu arabirimler bu nedenle değişmezdir. (Bu vesileyle, T sadece giriş pozisyonlarda kullanıldıysa bunlar kontra-varyant olurdu, ama bu gerçekten önemli burada yok.)

< ... kesik ...>

Yani, sorunuzu cevaplamak için,IEnumerable'dan miras alabiliyor çünkü! :-)

+1

Bu ilginç ... Gerçekten IList 'IList'i devralmadığı için IList ', ama varyansı hesaba katarsak, mantıklı olmaya başlar ... –

+1

Çok kötü Microsoft asla tanımlanamadı IReadableByIndex ve IReadableByIndex IList ve IList (Of T) tarafından kaleme alınmış olabilir. IReadableByIndex, zorlanmadan IReadableByIndex (Of T) tarafından kalıtılabilir ve salt okunur dizinlenebilir koleksiyonların varyansı çok güzel olurdu. – supercat

+0

@supercat Microsoft, namazınızı duymuş olabilir, çünkü bu yorumu yazdığınızdan beri, ['IReadOnlyList '] (http://msdn.microsoft.com/en-us/library/hh192385.aspx) 'yi tanıttılar. 'out'' T'de kovaryansı gösterir. –

16

IEnumerable cevabı şöyledir: "çünkü tür güvenliğinden etkilenmeyebilir".

IEnumerable bir "salt okunur" arabirimidir - bu nedenle, jenerik formun nongenerik formdan daha spesifik olması önemli değildir. İkisini de uygulayarak hiçbir şeyi kırmazsın. IEnumerator.Currentobject değerini döndürürken, IEnumerator<T>.CurrentT döndürür - bu her zaman doğru bir şekilde object dönüştürür olabileceğinden, boks yapmak anlamına gelebilir.

IList<T> ve IList ile karşılaştırın - o kadar da iyi herhangi bir IList<T> (aslında IList<object> dışında bir şey) geçersiz olabilir, oysa bir IList üzerinde Add(object) çağırabilir. Bu konuyla ilgili olarak Brad Abram'ın blogged with Anders' answer numaralı telefonuna başvurunuz.

2

Bu, jenerikleri desteklemeyen sınıflarla çalışacak şekilde olur. Ayrıca, .NET jenerikleri, IList < uzun> IList < int> gibi bir şey yapmanıza izin vermez; bu nedenle, sabit bir taban sınıfına veya arabirime ihtiyaç duyduğunuzda, arabirimlerin genel olmayan sürümleri oldukça yararlı olabilir.

+0

Bu önemli bir nokta. IList , IList 'a dönüştürülemez. –

3

Geriye dönük uyumluluk içindir. Bir .Net 1 çağırırsanız.IEnumerable bir jenerik IEnumerable beklediğiniz 1 fonksiyon jenerik IEnumerable içinde geçebilirsiniz.

Luckilly genel IEnumerator Genellikle bir sýralayýcý döndüren özel yöntem uygulamak ve daha sonra hem eski hem de yeni stil GetEnumerator yöntemi için geçmek eski tarz IEnumerator

devralır.

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

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

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { 
     return Enumerator(); 
    } 
+0

IEnumerable uygulandığında, özel IEnumerable.GetEnumerator() yöntemini de uygulamanız gerekir. Neyse ki, yukarıdaki kod gayet başarılı, bu yüzden çabaları çoğaltmıyorsunuz. – spoulson

+2

@spoulson: Özel değil. Bir arayüzün parçası, bu yüzden kamuya uygulanmalı. Mendelt'in örneği özel olarak uygulamıyor, bunu açıkça uygular, böylece sadece nesne IEnumerable'a gönderildiğinde kullanılabilir. –

+0

@spoulson: Görsel stüdyonun uygulama arayüzünü tıkladığımda ikinci iki yöntem üretildi, gerçekten bakmadı. System.Collections için bir kullanım ekleyebilir ve üçüncü işlevi açıkça herkese açık hale getirebilirsiniz. – Mendelt