Convertissez librement entre List <T> et IEnumerable <T>

103

Comment puis-je convertir un List<MyObject>en un IEnumerable<MyObject>puis inversement?

Je veux faire cela pour exécuter une série d'instructions LINQ sur la liste, par exemple Sort()

TK.
la source
C'est le couvert dans cette question stackoverflow.com/questions/31708/…
John

Réponses:

148
List<string> myList = new List<string>();
IEnumerable<string> myEnumerable = myList;
List<string> listAgain = myEnumerable.ToList();
Tamas Czinege
la source
30
Attention cependant que myEnumarable est la même instance d'objet que myList, mais listAgain n'est pas la même instance d'objet que myEnumerable. Selon ce que vous voulez faire et ce qu'est myEnumerable, "List <string> listAgain = myEnumerable as List <string>;" pourrait être mieux.
ChrisW
1
Chrisw: Oh oui, vous avez raison bien sûr, mais l'interface IEnumerable <T> est immuable donc elle ne causera pas de problèmes dans cette direction et le renvoi semble juste sale lorsque vous avez une fonction qui s'occupera de la sécurité des types.
Tamas Czinege
1
Vous pouvez également simplement utiliser l'objet myList d'origine. (Je suppose que je ne comprends pas vraiment la question)
qc
6
C'est juste que s'il édite myList alors il éditera myEnumrable, mais s'il édite listAgain alors il n'éditera pas myEnumerable.
ChrisW
15
N'oubliez pas using System.Linq;ou vous ne pourrez pas ToList ()
Jason
21

A List<T>est un IEnumerable<T>, donc en fait, il n'est pas nécessaire de «convertir» un List<T>en un IEnumerable<T>. Puisque a List<T>est un IEnumerable<T>, vous pouvez simplement affecter a List<T>à une variable de type IEnumerable<T>.

À l'inverse, tout IEnumerable<T>n'est pas un List<T>offcourse, vous devrez donc appeler la ToList()méthode membre du IEnumerable<T>.

Frederik Gheysels
la source
4
Techniquement, ToList est une méthode membre de System.Linq.Enumerable
Amy B
2
Je pense que vous pouvez simplement lancer IEnumerable sur la liste comme David le dit.
abatishchev le
9

A List<T>est déjà un IEnumerable<T>, vous pouvez donc exécuter des instructions LINQ directement sur votre List<T>variable.

Si vous ne voyez pas les méthodes d'extension LINQ comme OrderBy()je suppose, c'est parce que vous n'avez pas de using System.Linqdirective dans votre fichier source.

Vous devez cependant reconvertir le résultat de l'expression LINQ en un résultat List<T>explicite:

List<Customer> list = ...
list = list.OrderBy(customer => customer.Name).ToList()
Dan Berindei
la source
"Si vous ne voyez pas les méthodes d'extension LINQ comme OrderBy ()" C'était mon problème, merci.
RyPope
5

À part: Notez que les opérateurs LINQ standard (comme dans l'exemple précédent) ne modifient pas la liste existante - list.OrderBy(...).ToList()créeront une nouvelle liste basée sur la séquence réorganisée. Cependant, il est assez facile de créer une méthode d'extension qui vous permet d'utiliser des lambdas avec 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)));
}

Ensuite, vous pouvez utiliser:

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

Cela met à jour la liste existante de la même manière que d' List<T>.Sorthabitude.

Marc Gravell
la source
Une légère correction à cette déclaration: les opérateurs LINQ standard ne modifient pas la liste existante; au lieu de cela, ils créent un nouveau IEnumerable qui contient la logique nécessaire pour effectuer leur travail. Cependant, cette logique n'est pas réellement exécutée tant que IEnumerator n'est pas demandé.
Vojislav Stojkovic
@Vojislav - Je voulais dire dans le contexte de l'exemple précédent se terminant par ToList- Je clarifierai cependant.
Marc Gravell
1

Conversion List<T>enIEnumerable<T>

List<T>implémente IEnumerable<T>(et beaucoup d'autres tels que IList<T>, ICollection<T>), il n'est donc pas nécessaire de reconvertir une liste en IEnumerable car elle est déjàIEnumerable<T> .

Exemple:

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;

Vous pouvez également utiliser la Enumerable.AsEnumerable()méthode

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

Conversion IEnumerable<T>enList<T>

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

Ceci est utile dans Entity Framework .

Nipuna
la source
0

Pour éviter la duplication en mémoire, resharper suggère ceci:

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

.ToList () renvoie une nouvelle liste immuable. Ainsi, les modifications apportées à listAgain n'affectent pas maListe dans la réponse @Tamas Czinege. Ceci est correct dans la plupart des cas pour au moins deux raisons: cela permet d'éviter que des changements dans une zone affectent l'autre zone (couplage lâche), et c'est très lisible, car nous ne devrions pas concevoir de code avec des préoccupations de compilateur.

Mais il y a certains cas, comme être dans une boucle serrée ou travailler sur un système embarqué ou à faible mémoire, où les considérations du compilateur doivent être prises en compte.

TamusJRoyce
la source