858 Stimmen

IEnumerable vs. Liste - Was ist zu verwenden? Wie funktionieren sie?

Ich habe einige Zweifel darüber, wie Enumerators arbeiten, und LINQ. Betrachten Sie diese beiden einfachen Selects:

List<Animal> sel = (from animal in Animals 
                    join race in Species
                    on animal.SpeciesKey equals race.SpeciesKey
                    select animal).Distinct().ToList();

ou

IEnumerable<Animal> sel = (from animal in Animals 
                           join race in Species
                           on animal.SpeciesKey equals race.SpeciesKey
                           select animal).Distinct();

Ich habe die Namen meiner ursprünglichen Objekte geändert, damit dies wie ein allgemeineres Beispiel aussieht. Die Abfrage selbst ist nicht so wichtig. Was ich fragen möchte, ist dies:

foreach (Animal animal in sel) { /*do stuff*/ }
  1. Ich habe festgestellt, dass ich bei der Verwendung von IEnumerable Wenn ich debugge und "sel" inspiziere, was in diesem Fall die IEnumerable ist, hat sie einige interessante Mitglieder: "inner", "outer", "innerKeySelector" und "outerKeySelector", die letzten beiden scheinen Delegierte zu sein. Das "inner"-Mitglied enthält keine "Animal"-Instanzen, sondern eher "Species"-Instanzen, was für mich sehr seltsam war. Das "äußere" Element enthält "Animal"-Instanzen. Ich nehme an, dass die beiden Delegierten bestimmen, was hineinkommt und was herauskommt?

  2. Ich habe festgestellt, dass, wenn ich "Distinct" verwende, die "innere" 6 Elemente enthält (dies ist falsch, da nur 2 Distinct sind), aber die "äußere" enthält die richtigen Werte. Wieder, wahrscheinlich die delegierten Methoden bestimmen dies, aber dies ist ein bisschen mehr als ich über IEnumerable wissen.

  3. Und vor allem: Welche der beiden Optionen ist leistungsmäßig die beste?

Die böse Liste Konvertierung über .ToList() ?

Oder vielleicht direkt den Enumerator verwenden?

Wenn Sie können, erklären Sie bitte auch ein bisschen oder werfen einige Links, die diese Verwendung von IEnumerable erklären.

918voto

Chris Wenham Punkte 22761

IEnumerable beschreibt ein Verhalten, während List eine Implementierung dieses Verhaltens ist. Wenn Sie IEnumerable geben Sie dem Compiler die Möglichkeit, die Arbeit auf später zu verschieben und dabei möglicherweise zu optimieren. Wenn Sie ToList() verwenden, zwingen Sie den Compiler, die Ergebnisse sofort zu reifizieren.

Wenn ich LINQ-Ausdrücke "stapele", verwende ich IEnumerable Denn indem ich nur das Verhalten spezifiziere, gebe ich LINQ die Möglichkeit, die Auswertung aufzuschieben und das Programm möglicherweise zu optimieren. Erinnern Sie sich daran, dass LINQ das SQL zur Abfrage der Datenbank erst dann generiert, wenn Sie es aufzählen? Bedenken Sie dies:

public IEnumerable<Animals> AllSpotted()
{
    return from a in Zoo.Animals
           where a.coat.HasSpots == true
           select a;
}

public IEnumerable<Animals> Feline(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Felidae"
           select a;
}

public IEnumerable<Animals> Canine(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Canidae"
           select a;
}

Jetzt haben Sie eine Methode, die eine anfängliche Stichprobe ("AllSpotted") auswählt, sowie einige Filter. Jetzt können Sie also Folgendes tun:

var Leopards = Feline(AllSpotted());
var Hyenas = Canine(AllSpotted());

Ist es also schneller, List zu verwenden als IEnumerable ? Nur wenn Sie verhindern wollen, dass eine Abfrage mehr als einmal ausgeführt wird. Aber ist es insgesamt besser? Nun, im obigen Beispiel werden Leoparden und Hyänen in jede einzelne SQL-Abfrage und die Datenbank gibt nur die Zeilen zurück, die relevant sind. Hätten wir jedoch eine Liste von AllSpotted() dann kann es langsamer laufen, weil die Datenbank viel mehr Daten zurückgeben könnte, als tatsächlich benötigt werden, und wir vergeuden Zyklen, um die Filterung im Client durchzuführen.

In einem Programm kann es besser sein, die Umwandlung der Abfrage in eine Liste bis zum Ende aufzuschieben. Wenn ich also Leoparden und Hyänen mehr als einmal aufzählen möchte, würde ich dies tun:

List<Animals> Leopards = Feline(AllSpotted()).ToList();
List<Animals> Hyenas = Canine(AllSpotted()).ToList();

318voto

rubStackOverflow Punkte 4762

Es gibt einen sehr guten Artikel geschrieben von: Claudio Bernasconi's TechBlog hier: Wann sind IEnumerable, ICollection, IList und List zu verwenden?

Hier einige grundlegende Punkte zu Szenarien und Funktionen:

enter image description here enter image description here

159voto

Keith Punkte 141163

Eine Klasse, die implementiert IEnumerable ermöglicht Ihnen die Verwendung der foreach Syntax.

Im Grunde hat es eine Methode, um das nächste Element in der Sammlung zu erhalten. Es braucht nicht die ganze Sammlung im Speicher zu haben und weiß nicht, wie viele Elemente darin sind, foreach holt einfach den nächsten Artikel, bis er aufgebraucht ist.

Dies kann unter bestimmten Umständen sehr nützlich sein, z. B. wenn man bei einer großen Datenbanktabelle nicht die gesamte Tabelle in den Speicher kopieren möchte, bevor man mit der Verarbeitung der Zeilen beginnt.

Jetzt List implementiert IEnumerable , sondern stellt die gesamte Sammlung im Speicher dar. Wenn Sie eine IEnumerable und Sie rufen .ToList() erstellen Sie eine neue Liste mit dem Inhalt der Aufzählung im Speicher.

Ihr linq-Ausdruck gibt eine Aufzählung zurück, und standardmäßig wird der Ausdruck ausgeführt, wenn Sie mit der Option foreach . Eine IEnumerable linq-Anweisung wird ausgeführt, wenn Sie die foreach aber Sie können eine frühere Iteration erzwingen, indem Sie .ToList() .

Ich meine Folgendes:

var things = 
    from item in BigDatabaseCall()
    where ....
    select item;

// this will iterate through the entire linq statement:
int count = things.Count();

// this will stop after iterating the first one, but will execute the linq again
bool hasAnyRecs = things.Any();

// this will execute the linq statement *again*
foreach( var thing in things ) ...

// this will copy the results to a list in memory
var list = things.ToList()

// this won't iterate through again, the list knows how many items are in it
int count2 = list.Count();

// this won't execute the linq statement - we have it copied to the list
foreach( var thing in list ) ...

122voto

CAD bloke Punkte 8014

Ein entscheidender Unterschied wurde nicht erwähnt, ironischerweise in einer Frage, die als Duplikat dieser Frage geschlossen wurde.

IEnumerable ist schreibgeschützt und List nicht.

Véase Praktischer Unterschied zwischen List und IEnumerable

74voto

thecoop Punkte 43958

Das Wichtigste ist, dass bei der Verwendung von Linq die Abfrage nicht sofort ausgewertet wird. Sie wird nur als Teil der Iteration durch die resultierende IEnumerable<T> in einem foreach - Das ist es, was all die seltsamen Delegierten tun.

Das erste Beispiel wertet die Abfrage also sofort aus, indem es die ToList und stellt die Abfrageergebnisse in eine Liste ein.
Das zweite Beispiel gibt eine IEnumerable<T> die alle Informationen enthält, die für die spätere Ausführung der Abfrage erforderlich sind.

Was die Leistung angeht, lautet die Antwort es kommt darauf an . Wenn Sie die Ergebnisse auf einmal auswerten müssen (z. B. wenn Sie die Strukturen, die Sie abfragen, später ändern oder wenn Sie nicht wollen, dass die Iteration über die IEnumerable<T> zu lange dauern) eine Liste verwenden. Andernfalls verwenden Sie eine IEnumerable<T> . Standardmäßig sollte die On-Demand-Auswertung im zweiten Beispiel verwendet werden, da diese im Allgemeinen weniger Speicherplatz benötigt, es sei denn, es gibt einen besonderen Grund, die Ergebnisse in einer Liste zu speichern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X