Antworten:
IEnumerable bietet nur minimale "iterierbare" Funktionen. Sie können die Sequenz durchlaufen, aber das war es auch schon. Dies hat Nachteile - zum Beispiel ist es sehr ineffizient, Elemente mit IEnumerable zu zählen oder das n-te Element zu erhalten - aber es hat auch Vorteile - zum Beispiel könnte ein IEnumerable eine endlose Folge sein, wie die Folge von Primzahlen.
Array ist eine Sammlung mit fester Größe und wahlfreiem Zugriff (dh Sie können sie indizieren).
List ist eine Sammlung variabler Größe (dh Sie können Elemente hinzufügen und entfernen) mit wahlfreiem Zugriff.
IList ist eine Schnittstelle, die Listenfunktionen (Zählen, Hinzufügen, Entfernen, Indexerzugriff) von den verschiedenen konkreten Klassen wie List, BindingList, ObservableCollection usw. abstrahiert.
IEnumerable ist eine Schnittstelle, die die Iteration durch eine Sammlung von Elementen ermöglicht (z. B. über das Schlüsselwort foreach).
Ein Array ist ein intrinsisches .NET. Es enthält Elemente des gleichen Typs, hat jedoch eine feste Größe. Sobald Sie ein Array mit x Elementen erstellt haben, kann es nicht mehr wachsen oder schrumpfen.
IList definiert die Schnittstelle für eine Liste und implementiert auch IEnumerable.
List implementiert die IList-Schnittstelle. Es ist eine konkrete Art von Liste.
Der Unterschied zwischen .NET-Listen und Arrays besteht darin, dass Listen Elemente hinzugefügt werden können - sie werden groß genug, um alle erforderlichen Elemente aufzunehmen. Die Liste speichert dies intern in einem Array. Wenn das Array nicht mehr groß genug ist, um alle Elemente aufzunehmen, wird ein neues Array erstellt und die Elemente kopiert.
IList & Arrays implementieren beide IEnumerable. So funktionieren Schnittstellen - Klassen implementieren den Vertrag und verhalten sich ähnlich und können daher ähnlich behandelt werden (Sie wissen, dass die Klasse IEnumerable implementiert, Sie müssen nicht wissen, wie oder warum). Ich schlage vor, Sie lesen über Schnittstellen und so weiter.
IEnumerable und IList sind Schnittstellen . Array und Liste sind Klassen. Array implementiert IEnumerable. List implementiert IList, das IEnumerable erweitert.
Bearbeiten: Wie in einem Kommentar erwähnt, implementiert Array auch IList.
Die Generierung einer IEnumerable-Sammlung ist faul. Beispiel:
public IEnumerable<int> GetTwoInts()
{
yield return 1;
yield return 2;
}
public void Something()
{
var twoInts = GetTwoInts();
}
In der Methode Something führt der Aufruf von GetTwoInts () nicht dazu, dass die Methode GetTwoInts ausgeführt wird, da die Aufzählung nie wiederholt wird.
twoIntsein foreachoder anrufen twoInts.ToList().
IEnumerableist eine allgemeine Schnittstelle , die von vielen Klassen verwendet wird, wie zum Beispiel Array, Listund Stringum jemanden Iterierte über eine Sammlung zu lassen. Grundsätzlich ist es das, was die foreachAussage antreibt .
IListIn der Regel stellen Sie ListEndbenutzern Variablen des Typs zur Verfügung. Diese Schnittstelle ermöglicht den wahlfreien Zugriff auf die zugrunde liegende Sammlung.
Beachten Sie zur Ergänzung der anderen Antworten, dass zwischen und beim Ausführen einer foreach-Anweisung ein Leistungsunterschied besteht .IList<T>List<T>
Dies liegt daran, dass das von zurückgegebene Iteratorobjekt ein Werttyp List<T>.GetEnumeratorist, während das von zurückgegebene Objekt IList<T>.GetEnumeratorein Referenztyp ist und daher eine Speicherzuordnung erfordert (siehe Enumerator des Wertetyps der Liste in c # ).
Meiner Meinung nach IList<T>ist das sowieso keine sehr gute Schnittstelle. Zum Beispiel Addkann der Aufruf werfen (siehe Warum Array IList implementiert? ). Wenn Sie Verkapselung würden Sie besser dran , mit IEnumerable<T>oder IReadOnlyList<T>.
Neben anderen Antworten kann das Verständnis der Unterschiede zwischen Enumerable und List / Array bei Verwendung von LINQ enorme Auswirkungen auf die Leistung haben. Kurz gesagt, Enumerable kann als Abfrage-Generator wahrgenommen werden, während List / Array das Ergebnis der Abfrage ist.
Im Kontext von LINQ to SQL mit EntityFramework erstellt der erstere lediglich die SQL-Abfrage, ohne sie für die Datenbank auszuführen oder Daten in den Speicher zu laden, während der letztere das Gegenteil ist. Aus diesem Grund würden wir den Anruf verschieben, .ToList()bis wir ihn im Speicher benötigen, um die Geschäftslogik auszuführen.
In einem anderen Kontext verzögert der LINQ-Ausdruck, der IEnumerable zurückgibt, die Ausführung, bis er .ToList()aufgerufen wird. Betrachten Sie das folgende Beispiel:
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
----------
Im ersten Beispiel werden zwei .Where()"angehängt" und am Ende zusammen ausgeführt, wenn .ToList()aufgerufen wird, wobei Element " A " zuerst durch die Pipe geht, dann Element " B ", wodurch " AABB " in der Ausgabe angezeigt wird, während im zweiten Beispiel " Das .Where()wird jedes Mal ausgeführt, wenn wir .ToList()unmittelbar danach aufrufen und daher " CD " und dann wieder " CD " sehen, zweimal ausgegeben. Daher kostet jedes Mal, wenn eine Aufzählung in eine Liste oder ein Array konvertiert wird, eine O (n) -Iteration über alle Elemente in der Sammlung, was sich auf die Leistung auswirkt, wenn die Sammlung groß ist.
Wir tendieren zwar nicht dazu, Code auf diese Weise zu schreiben, indem wir .ToList()zwischen LINQ-Aufrufen aufrufen, aber es würde häufiger vorkommen, wenn wir Code in wiederverwendbare Methoden einbeziehen, die List/Arrayeher zurückgeben als IEnumerable.
Dies bedeutet jedoch nicht, dass wir immer operieren sollten IEnumerable. Wie von Towlson erwähnt , führen Operationen wie .Count()die Iteration über die Sammlung aus, während für eine Liste oder ein Array diese Informationen vorberechnet werden und die Konvertierung in List/Arrayeffizienter ist, wenn Sie .Count()mehrere Aufrufe planen . Dies ist auch der Grund, warum .Counteine Liste eine Eigenschaft enthält und keine .Count()Methode zum Zählen.
Dies ist ein alter Beitrag, aber ich dachte immer noch daran zu antworten. IEnumerable ist ein Verhalten, während Array eine Datenstruktur ist (zusammenhängende Sammlung von Elementen mit fester Größe, die den Zugriff auf Elemente über Indizes erleichtert). Wenn ein Array IEnumerable implementiert, soll es auch die inhärente Eigenschaft IEnumerable darstellen (um die Iteration über die Sammlung zu erleichtern).