Jaka jest różnica między IEnumerablei Array?
Jaka jest różnica między IListi List?
Wydaje się, że mają tę samą funkcję.
Odpowiedzi:
IEnumerable zapewnia tylko minimalną „iterowalną” funkcjonalność. Możesz przejść przez sekwencję, ale to wszystko. Ma to wady - na przykład zliczanie elementów za pomocą IEnumerable lub uzyskiwanie n-tego elementu jest bardzo nieefektywne - ale ma też zalety - na przykład IEnumerable może być sekwencją nieskończoną, podobnie jak sekwencja liczb pierwszych.
Tablica jest kolekcją o stałym rozmiarze i dostępie swobodnym (tzn. Można ją indeksować).
Lista jest kolekcją o zmiennej wielkości (tzn. Możesz dodawać i usuwać elementy) z dostępem swobodnym.
IList to interfejs, który abstrahuje funkcje list (zliczanie, dodawanie, usuwanie, dostęp do indeksatora) z dala od różnych konkretnych klas, takich jak List, BindingList, ObservableCollection itp.
IEnumerable to interfejs, który umożliwia iterację poprzez kolekcję elementów (np. Poprzez słowo kluczowe foreach).
Tablica jest wewnętrzną częścią platformy .NET. Przechowuje przedmioty tego samego typu, ale ma ustalony rozmiar. Po utworzeniu tablicy z elementami x nie może ona rosnąć ani się zmniejszać.
IList definiuje interfejs dla listy, a także implementuje IEnumerable.
List implementuje interfejs IList; jest to konkretny typ listy.
Różnica między listami .NET a tablicami polega na tym, że do list można dodawać elementy - rosną one na tyle, aby były wystarczająco duże, aby pomieścić wszystkie wymagane elementy. Lista przechowuje to wewnętrznie w tablicy, a gdy tablica nie jest już wystarczająco duża, aby pomieścić wszystkie elementy, tworzona jest nowa tablica i elementy są kopiowane w poprzek.
IList i tablice implementują IEnumerable. Tak właśnie działają interfejsy - klasy implementują kontrakt i zachowują się w podobny sposób iw rezultacie można je traktować podobnie (wiesz, że klasa implementuje IEnumerable, nie musisz znać hows ani dlaczego). Proponuję przeczytać o interfejsach i tak dalej.
IEnumerable i IList to interfejsy . Array i List to klasy. Array implementuje IEnumerable. List implementuje IList, który rozszerza IEnumerable.
Edycja: jak wspomniał itowlson w komentarzu, Array implementuje również IList.
Generowanie kolekcji IEnumerable jest leniwe. Przykład:
public IEnumerable<int> GetTwoInts()
{
yield return 1;
yield return 2;
}
public void Something()
{
var twoInts = GetTwoInts();
}
W metodzie Coś wywołanie GetTwoInts () nie spowoduje w rzeczywistości wykonania metody GetTwoInts, ponieważ wyliczenie nigdy nie jest iterowane.
twoIntsw foreachlub zaproszenia twoInts.ToList().
IEnumerableJest to interfejs ogólnego przeznaczenia, który jest używany przez wiele klas, takich jak Array, Listi Stringżeby pozwolić komuś iteracyjne nad kolekcji. Zasadniczo to jest to, co napędza foreachoświadczenie.
IListpolega zazwyczaj na ujawnianiu zmiennych typu Listużytkownikom końcowym. Ten interfejs umożliwia losowy dostęp do podstawowej kolekcji.
Aby uzupełnić inne odpowiedzi, zwróć uwagę, że istnieje różnica w wydajności między IList<T>i List<T>podczas wykonywania instrukcji foreach.
Dzieje się tak, ponieważ obiekt iteratora zwracany przez List<T>.GetEnumeratorjest typem wartości, podczas gdy ten zwracany przez IList<T>.GetEnumeratorjest typem referencyjnym, a zatem wymaga alokacji pamięci (zobacz moduł wyliczający typ wartości listy w języku C # ).
Moim zdaniem i IList<T>tak nie jest to zbyt dobry interfejs. Na przykład wywołanie Addmoże throw (zobacz Dlaczego tablica implementuje IList? ). Jeśli potrzebujesz hermetyzacji, lepiej użyj IEnumerable<T>lub IReadOnlyList<T>.
Oprócz innych odpowiedzi zrozumienie różnicy między Enumerable a List / Array podczas korzystania z LINQ może mieć ogromny wpływ na wydajność. Krótko mówiąc, Enumerable może być postrzegane jako konstruktor zapytań, podczas gdy List / Array jest wynikiem zapytania.
W kontekście LINQ to SQL przy użyciu EntityFramework, pierwsza z nich po prostu tworzy zapytanie SQL bez wykonywania go w bazie danych ani ładowania żadnych danych do pamięci, podczas gdy później jest odwrotnie. Dlatego odłożyliśmy telefon.ToList() dopóki nie będziemy go potrzebować w pamięci do wykonywania logiki biznesowej.
W innym kontekście wyrażenie LINQ zwracające IEnumerable odroczy wykonanie do momentu .ToList()wywołania. Rozważ poniższy przykład:
void Main()
{
var w1 = "AB".AsEnumerable();
Console.WriteLine($"W1: 1");
w1 = w1.Where(W1);
Console.WriteLine($"W1: 2");
w1 = w1.Where(W2);
Console.WriteLine($"W1: 3");
w1.ToList();
Console.WriteLine($"----------");
var w2 = "CD".AsEnumerable();
Console.WriteLine($"W2: 1");
w2 = w2.Where(W1);
Console.WriteLine($"W2: 2");
w2 = w2.ToList();
Console.WriteLine($"W2: 3");
w2 = w2.Where(W2);
Console.WriteLine($"W2: 4");
w2.ToList();
Console.WriteLine($"----------");
}
bool W1(char arg)
{
Console.WriteLine($"W1:{arg}");
return true;
}
bool W2(char arg)
{
Console.WriteLine($"W2:{arg}");
return true;
}
OUTPUT:
W1: 1
W1: 2
W1: 3
W1:A
W2:A
W1:B
W2:B
----------
W2: 1
W2: 2
W1:C
W1:D
W2: 3
W2: 4
W2:C
W2:D
----------
W pierwszym przykładzie dwa .Where()są „dołączane” i wykonywane razem na końcu, gdy .ToList()jest wywoływane z elementem „ A ” przechodzącym najpierw przez potok, a następnie elementem „ B ”, co powoduje wyświetlenie „ AABB ” na wyjściu, podczas gdy w drugim przykładzie, .Where()jest wykonywana za każdym razem, gdy wzywamy .ToList()natychmiast potem, stąd widząc „ CD ”, a następnie „ CD ” znowu wyjście dwukrotnie. Dlatego za każdym razem, gdy Enumerable jest konwertowany na listę lub tablicę, będzie kosztować jedno O (n) iterację wszystkich elementów w kolekcji, co będzie miało wpływ na wydajność, gdy kolekcja jest duża.
Chociaż nie mamy tendencji do pisania kodu w ten sposób, wywołując .ToList()między wywołaniami LINQ, ale zdarza się to częściej, gdy uwzględniamy kod w metodach wielokrotnego użytku, które zwracają, List/Arraya nie IEnumerable.
Nie oznacza to jednak, że powinniśmy zawsze działać IEnumerable. Jak wspomniał Towlson , te operacje, takie jak .Count()spowodują iterację kolekcji, podczas gdy lista lub tablica miałyby te informacje wstępnie obliczone, a zatem konwersja na List/Arraybyłaby bardziej wydajna, jeśli planujesz wywoływać .Count()wiele razy. Dlatego też .Countna liście znajduje się właściwość, a nie .Count()metoda jej liczenia.
To jest stary post, ale wciąż myślę o udzieleniu odpowiedzi. IEnumerable to zachowanie, podczas gdy Array jest strukturą danych (ciągła kolekcja elementów o stałym rozmiarze, ułatwiająca dostęp do elementów za pomocą indeksów). Gdy Array implementuje IEnumerable, ma również przedstawiać nieodłączną właściwość IEnumerable (ułatwiając iterację kolekcji).