2011-02-11 37 views
37

Jaka jest różnica między IEnumerable a IEnumerable<T>?Różnica między IEnumerable i IEnumerable <T>?

Widziałem wiele klas ramowych implementujących oba te interfejsy, dlatego chciałbym wiedzieć, jakie korzyści można uzyskać, implementując oba?

Proszę spojrzeć, jak zostały one zdefiniowane:

public interface IEnumerable 
{ 
    [DispId(-4)] 
    IEnumerator GetEnumerator(); 
} 
public interface IEnumerable<T> : IEnumerable 
{ 
    IEnumerator<T> GetEnumerator(); 
} 

Jak widzimy, IEnumerable<T> wynika z IEnumerable, co oznacza, że ​​ma cokolwiek IEnumerable, IEnumerable<T> dziedziczy, to dlaczego my realizować zarówno zamiast tylko IEnumerable<T> ? Wdraża IEnumerable<T> za mało?

Podobnie, istnieją inne podobne pary:

  • IList i IList<T>
  • ICollection i ICollection<T>

chciałbym wiedzieć o nich, jak również.

Odpowiedz

48

Zasadniczo na pierwszym miejscu pojawiły się interfejsy niegencze, w .NET 1.0 i 1.1. Następnie, gdy pojawił się .NET 2.0, wyłoniły się generyczne odpowiedniki. Życie byłoby o wiele prostsze, gdyby leki generyczne uczynił go w .NET 1.0 :)

Pod względem wdrażania „tylko” IEnumerable<T> zamiast obie - w zasadzie mieć wdrożyć zarówno i trzeba użyć wyraźny interfejs implementacja, biorąc pod uwagę, że oba definiują bez parametrów metodę. Jak IEnumerator<T> rozciąga IEnumerator zbyt, to zazwyczaj coś takiego:

public IEnumerator<T> GetEnumerator() 
{ 
    // Return real iterator 
} 

// Explicit implementation of nongeneric interface 
IEnumerator IEnumerable.GetEnumerator() 
{ 
    // Delegate to the generic implementation 
    return GetEnumerator(); 
} 

Z drugiej strony, z bloków iterator wprowadzonych w C# 2 (z yield return etc) rzadko potrzebne do realizacji tych rzeczy w całości ręcznie, na szczęście. Może być konieczne napisanie czegoś podobnego do powyższego, a następnie użycie metody yield return w metodzie GetEnumerator.

Zauważ, że IList<T> robi nie przedłużyć IList i ICollection<T> robi nie przedłużyć ICollection. Dzieje się tak dlatego, że jest to mniej bezpieczne dla tego rodzaju ... podczas gdy dowolny ogólny iterator może być postrzegany jako nie-generyczny iterator ze względu na (potencjalnie boksujący) konwersję dowolnej wartości na wartości i , które dodają do kolekcja; i nie ma sensu dodawać (powiedzmy) ciągu do IList<int>.

EDYCJA: Powodem, dla którego potrzebujemy IEnumerable<T> jest to, że możemy dokonywać iteracji w sposób bezpieczny i propagować tę informację. Jeśli zwrócę Ci wiadomość IEnumerable<string>, wiesz, że możesz bezpiecznie założyć, że wszystko, co z niej zostanie zwrócone, będzie referencją do łańcucha lub wartością pustą. W przypadku IEnumerable musieliśmy skutecznie rzutować (często niejawnie w oświadczeniu foreach) każdy element, który został zwrócony z sekwencji, ponieważ właściwość Current z IEnumerator jest właśnie typu object.Jeśli chodzi o to, dlaczego nadal potrzebujemy potrzebujemy IEnumerable - ponieważ stare interfejsy nigdy nie znikają, w zasadzie. Używa go zbyt wiele istniejącego kodu.

Byłoby możliwe IEnumerable<T> nie przedłużyć IEnumerable, ale potem każdy kod chcąc skorzystać z IEnumerable<T> nie mógł zadzwonić do metody przyjmowania IEnumerable - i nie było wiele takich metod, które z .NET 1.1 i 1.0.

+12

+1 Życie byłoby o wiele prostsze, gdyby leki generyczne znalazły się w .NET 1.0 ... – Oded

+0

@Jon: pytanie brzmi: dlaczego potrzebujemy nawet zaimplementować 'IEnumerable' kiedy już implementujemy' IEnumerable ' , lub odwrotnie? – Nawaz

+0

@Nawaz: Edytowałem swoją odpowiedź. Jak wygodnie jesteś w idei, dlaczego generics są dobre? –

5

Jeden zwraca obiekt typu Object, drugi zwraca obiekt typu T.

2

Jak widać, dlaczego klasy określające zarówno wystarczająco chociaż IEnumerable < T> implementuje IEnumerable, to nie jest potrzebne, ale to jest miłe w samoobsługowym dokumentowaniu, aby czasami wymieniać pod-interfejsy. Rozważmy

interface IA { } 
interface IB : IA { } 

class A : IB {} // legal, IB implements IA 

class B : IA, IB {} // also legal, possible more clear on intent 
1

Podczas iteracja pętli IEnumerator utrzymuje ten stan. Zapamiętuje położenie kursora, a IEnumerable nie.

Powiązane problemy