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.
+1 Życie byłoby o wiele prostsze, gdyby leki generyczne znalazły się w .NET 1.0 ... – Oded
@Jon: pytanie brzmi: dlaczego potrzebujemy nawet zaimplementować 'IEnumerable' kiedy już implementujemy' IEnumerable ' , lub odwrotnie? –
Nawaz
@Nawaz: Edytowałem swoją odpowiedź. Jak wygodnie jesteś w idei, dlaczego generics są dobre? –