Konvertieren Sie frei zwischen List <T> und IEnumerable <T>

103

Wie kann ich ein List<MyObject>in ein IEnumerable<MyObject>und dann wieder zurück konvertieren ?

Ich möchte dies tun, um eine Reihe von LINQ-Anweisungen in der Liste auszuführen, z Sort()

TK.
quelle
Dies ist die in dieser Frage behandelte stackoverflow.com/questions/31708/…
John

Antworten:

148
List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myEnumerable.ToList();
Tamas Czinege
quelle
30
Beachten Sie jedoch, dass myEnumarable dieselbe Objektinstanz wie myList ist, listAgain jedoch nicht dieselbe Objektinstanz wie myEnumerable. Abhängig davon, was Sie tun möchten und was myEnumerable ist, "List <string> listAgain = myEnumerable as List <string>;" könnte besser sein.
ChrisW
1
Chrisw: Oh ja, Sie haben natürlich Recht, aber die IEnumerable <T> -Schnittstelle ist unveränderlich, sodass sie keine Probleme in diese Richtung verursacht. Das Zurückwerfen fühlt sich nur schmutzig an, wenn Sie eine Funktion haben, die sich um die Typensicherheit kümmert.
Tamas Czinege
1
Sie können auch einfach das ursprüngliche myList-Objekt verwenden. (Ich glaube, ich verstehe die Frage nicht wirklich)
etw
6
Es ist nur so, dass er myEnumrable bearbeiten würde, wenn er myList bearbeitet, aber wenn er listAgain bearbeitet, würde er myEnumerable nicht bearbeiten.
ChrisW
15
Vergiss nicht using System.Linq;oder du wirst nicht in der Lage sein, ToList ()
Jason
21

A List<T>ist ein IEnumerable<T>, also besteht eigentlich keine Notwendigkeit, a List<T>in ein umzuwandeln IEnumerable<T>. Da a ein List<T>ist IEnumerable<T>, können Sie a einfach List<T>einer Variablen vom Typ zuweisen IEnumerable<T>.

Umgekehrt ist nicht jeder IEnumerable<T>ein List<T>Offcourse, daher müssen Sie die ToList()Member-Methode von aufrufen IEnumerable<T>.

Frederik Gheysels
quelle
4
Technisch gesehen ist ToList eine Mitgliedsmethode von System.Linq.Enumerable
Amy B
2
Ich denke, Sie können IEnumerable einfach auf List setzen, wie David es sagt.
Abatishchev
9

A List<T>ist bereits ein IEnumerable<T>, sodass Sie LINQ-Anweisungen direkt für Ihre List<T>Variable ausführen können .

Wenn Sie die LINQ-Erweiterungsmethoden nicht so sehen, wie OrderBy()ich vermute, liegt das daran, dass using System.LinqIhre Quelldatei keine Direktive enthält.

Sie müssen das Ergebnis des LINQ-Ausdrucks jedoch List<T>explizit wieder in ein Ergebnis konvertieren :

List<Customer> list = ...
list = list.OrderBy(customer => customer.Name).ToList()
Dan Berindei
quelle
"Wenn Sie die LINQ-Erweiterungsmethoden wie OrderBy () nicht sehen" Das war mein Problem, danke.
RyPope
5

Nebenbei: Beachten Sie, dass die Standard-LINQ-Operatoren (wie im vorherigen Beispiel) die vorhandene Liste nicht ändern. Sie list.OrderBy(...).ToList()erstellen eine neue Liste basierend auf der neu geordneten Reihenfolge. Es ist jedoch ziemlich einfach, eine Erweiterungsmethode zu erstellen, mit der Sie Lambdas verwenden können mit List<T>.Sort:

static void Sort<TSource, TValue>(this List<TSource> list,
    Func<TSource, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    list.Sort((x,y) => comparer.Compare(selector(x), selector(y)));
}

static void SortDescending<TSource, TValue>(this List<TSource> list,
    Func<TSource, TValue> selector)
{
    var comparer = Comparer<TValue>.Default;
    list.Sort((x,y) => comparer.Compare(selector(y), selector(x)));
}

Dann können Sie verwenden:

list.Sort(x=>x.SomeProp); // etc

Dadurch wird die vorhandene Liste auf die gleiche Weise aktualisiert , wie dies List<T>.Sortnormalerweise der Fall ist.

Marc Gravell
quelle
Eine leichte Korrektur dieser Aussage: Die Standard-LINQ-Operatoren ändern die vorhandene Liste nicht. Stattdessen erstellen sie eine neue IEnumerable, die die für ihre Arbeit erforderliche Logik enthält. Diese Logik wird jedoch erst ausgeführt, wenn der IEnumerator angefordert wird.
Vojislav Stojkovic
@Vojislav - Ich meinte im Kontext des früheren Beispiels, das mit endet ToList- ich werde es jedoch klarstellen.
Marc Gravell
1

Konvertieren List<T>inIEnumerable<T>

List<T>implementiert IEnumerable<T>(und viele andere wie IList<T>, ICollection<T>), daher besteht keine Notwendigkeit, eine Liste zurück in IEnumerable zu konvertieren, da es bereits eine IEnumerable<T>.

Beispiel:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Person person1 = new Person() { Id = 1, Name = "Person 1" };
Person person2 = new Person() { Id = 2, Name = "Person 2" };
Person person3 = new Person() { Id = 3, Name = "Person 3" };

List<Person> people = new List<Person>() { person1, person2, person3 };

//Converting to an IEnumerable
IEnumerable<Person> IEnumerableList = people;

Sie können auch die Enumerable.AsEnumerable()Methode verwenden

IEnumerable<Person> iPersonList = people.AsEnumerable();

Konvertieren IEnumerable<T>inList<T>

IEnumerable<Person> OriginallyIEnumerable = new List<Person>() { person1, person2 };
List<Person> convertToList = OriginallyIEnumerable.ToList();

Dies ist in Entity Framework nützlich .

Nipuna
quelle
0

Um Doppelarbeit im Speicher zu vermeiden, schlägt resharper Folgendes vor:

List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myList as List<string>() ?? myEnumerable.ToList();

.ToList () gibt eine neue unveränderliche Liste zurück. Änderungen an listAgain wirken sich also nicht auf myList in der Antwort von @Tamas Czinege aus. Dies ist in den meisten Fällen aus mindestens zwei Gründen richtig: Dies verhindert Änderungen in einem Bereich, die sich auf den anderen Bereich auswirken (lose Kopplung), und ist sehr gut lesbar, da wir keinen Code mit Compiler-Bedenken entwerfen sollten.

Es gibt jedoch bestimmte Fälle, z. B. in einer engen Schleife oder bei der Arbeit an einem eingebetteten System oder einem System mit wenig Arbeitsspeicher, bei denen Compiler-Überlegungen berücksichtigt werden sollten.

TamusJRoyce
quelle