Quelle est la différence entre IEnumerable et Array, IList et List?


91

Quelle est la différence entre IEnumerableet Array?

Quelle est la différence entre IListet List?

Ceux-ci semblent avoir la même fonction.

Réponses:


101

IEnumerable ne fournit que des fonctionnalités "itérables" minimales. Vous pouvez parcourir la séquence, mais c'est à peu près tout. Cela présente des inconvénients - par exemple, il est très inefficace de compter les éléments en utilisant IEnumerable, ou d'obtenir le nième élément - mais cela présente également des avantages - par exemple, un IEnumerable pourrait être une séquence sans fin, comme la séquence de nombres premiers.

Array est une collection de taille fixe avec un accès aléatoire (c'est-à-dire que vous pouvez y indexer).

List est une collection de taille variable (c'est-à-dire que vous pouvez ajouter et supprimer des éléments) avec un accès aléatoire.

IList est une interface qui fait abstraction des fonctionnalités de liste (comptage, ajout, suppression, accès indexeur) des différentes classes concrètes telles que List, BindingList, ObservableCollection, etc.


2
Selon la réponse acceptée ici, stackoverflow.com/questions/1826658/… . Count on IEnumerable est presque le même car il tente d'appeler Count on ICollection
Karsten

15
Oui et non. La méthode d'extension Count () vérifie si IEnumerable est également une ICollection et appelle sa propriété Count si c'est le cas. Si IEnumerable n'est pas une ICollection, Count () revient à l'itération de la séquence. J'aurais peut-être dû dire "il est très inefficace de compter les éléments en utilisant uniquement IEnumerable", car bien sûr, la présence de IEnumerable ne vous empêche pas d'utiliser une méthode plus efficace si l'objet en a une, et les méthodes d'extension LINQ to Objects font exactement cette.
itowlson

17

IEnumerable est une interface qui permet l'itération à travers une collection d'éléments (par exemple via le mot-clé foreach).

Un tableau est un intrinsèque .NET. Il contient des éléments du même type, mais de taille fixe. Une fois que vous avez créé un tableau avec x éléments, il ne peut ni s'agrandir ni se réduire.

IList définit l'interface d'une liste et implémente également IEnumerable.

List implémente l'interface IList; c'est un type concret de liste.

La différence entre les listes .NET et les tableaux est que les listes peuvent avoir des éléments ajoutés - elles deviennent suffisamment grandes pour contenir tous les éléments requis. La liste stocke cela en interne dans un tableau et, lorsque le tableau n'est plus assez grand pour contenir tous les éléments, un nouveau tableau est créé et les éléments copiés.

IList et les tableaux implémentent tous deux IEnumerable. C'est ainsi que fonctionnent les interfaces - les classes implémentent le contrat et se comportent de manière similaire et peuvent être traitées de la même manière en conséquence (vous savez que la classe implémente IEnumerable, vous n'avez pas besoin de connaître le comment ou le pourquoi). Je vous suggère de lire sur les interfaces et ainsi de suite.


1
Ajout de ce commentaire pour les lecteurs qui ne lisent pas toutes les réponses: les tableaux et List <> implémentent tous deux IList <> (les tableaux implémentent une grande partie de celui-ci de manière explicite, probablement parce que de nombreux membres lancent une NotSupportedException). Il est également plus correct de dire que IList hérite de IEnumerable que de dire qu'il l'implémente.
phoog

9

IEnumerable et IList sont des interfaces . Array et List sont des classes. Array implémente IEnumerable. List implémente IList qui étend IEnumerable.

Edit: comme itowlson l'a mentionné dans un commentaire, Array implémente également IList.


Moi non plus! Que se passe-t-il si vous commencez à appeler IList.RemoveAt sur un tableau, cependant?
Mark Simpson

Il lève une NotSupportedException. (Remarque IList.RemoveAt et les méthodes IList similaires sont implémentées explicitement sur Array afin qu'elles n'apparaissent pas sur une référence Array normale!)
itowlson

1
@itowlson Je ferais remarquer que seul System.Array (une classe en soi) implémente IList, mais T [] n'implémente pas IList <T>. T [] implémente IEnumerable <T> à la place. Je pense que l'OP n'a pas nécessairement demandé System.Array en demandant "Array" IMHO
usr-local-ΕΨΗΕΛΩΝ

6

La génération d'une collection IEnumerable est paresseuse. Exemple:

public IEnumerable<int> GetTwoInts()
{
  yield return 1;
  yield return 2;
}
public void Something()
{
  var twoInts = GetTwoInts();
}

Dans la méthode Something l'appel à GetTwoInts () n'entraînera pas réellement l'exécution de la méthode GetTwoInts puisque l'énumération n'est jamais répétée.


Pourriez-vous s'il vous plaît élaborer un peu? Je ne sais pas si j'ai bien compris. Pouvez-vous afficher plus tard une ligne de code qui entraînera réellement l'exécution de cette méthode? Merci!
paaone le

@paaone a mis twoIntsun foreachappel ou twoInts.ToList().
row1

2

IEnumerableest une interface à usage général qui est utilisée par de nombreuses classes, telles que Array, ListetString afin de laisser quelqu'un d' itérer sur une collection. Fondamentalement, c'est ce qui motive la foreachdéclaration.

IListest généralement la manière dont vous exposez les variables de type Listaux utilisateurs finaux. Cette interface permet un accès aléatoire à la collection sous-jacente.


2

Pour compléter les autres réponses, notez qu'il existe une différence de performance entre IList<T>etList<T> lors de l'exécution d'une instruction foreach.

C'est parce que l'objet itérateur retourné par List<T>.GetEnumeratorest un type valeur alors que celui retourné par IList<T>.GetEnumeratorest un type référence, et nécessite donc une allocation de mémoire (voir Enumérateur de type valeur de liste en c # ).

À mon avis, ce IList<T>n'est pas une très bonne interface de toute façon. Par exemple, l'appel Addpeut lancer (voir Pourquoi un tableau implémente IList? ). Si vous avez besoin d'encapsulation, vous feriez mieux d'utiliser IEnumerable<T>ou IReadOnlyList<T>.


1

En plus d'autres réponses, comprendre la différence entre Enumerable et List / Array lors de l'utilisation de LINQ peut avoir un impact énorme sur les performances. En bref, Enumerable peut être perçu comme un générateur de requête tandis que List / Array est le résultat de la requête.

Dans le contexte de LINQ to SQL utilisant EntityFramework, le premier construit simplement la requête SQL sans l'exécuter sur la base de données ni charger de données en mémoire tandis que le second est le contraire. C'est pourquoi nous différerions l'appel .ToList()jusqu'à ce que nous en ayons besoin dans la mémoire pour exécuter la logique métier.

Dans un autre contexte, l'expression LINQ renvoyant IEnumerable reportera l'exécution jusqu'à ce qu'elle .ToList()soit appelée. Prenons l'exemple ci-dessous:

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
----------

Dans le premier exemple, deux .Where()sont "ajoutés" et exécutés ensemble à la fin quand .ToList()est appelé avec l'élément " A " passant par le tube d'abord puis l'élément " B ", d'où " AABB " dans la sortie, tandis que dans le deuxième exemple, le .Where()est exécuté à chaque fois si nous appelons .ToList()immédiatement après, donc voir " CD " puis " CD " à nouveau, sortie deux fois. Par conséquent, chaque fois qu'un Enumerable est converti en List ou en Array coûtera une itération O (n) sur tous les éléments de la collection, ce qui aura un impact sur les performances lorsque la collection est grande.

Bien que nous n'ayons pas tendance à écrire du code de cette façon en appelant .ToList()entre les appels LINQ, cela se produirait plus fréquemment lorsque nous factorisons le code dans des méthodes réutilisables qui retournent List/Arrayplutôt que IEnumerable.

Cependant, cela ne signifie pas que nous devons toujours opérer IEnumerable. Comme mentionné par towlson , les opérations telles que .Count()provoqueront une itération sur la collection tandis qu'une liste ou un tableau aurait cette information pré-calculée et donc la conversion en List/Arrayserait plus efficace si vous prévoyez d'appeler .Count()plusieurs fois. C'est aussi pourquoi il existe une .Countpropriété sur une liste plutôt qu'une .Count()méthode pour la compter.


0

C'est un ancien message, mais je pense toujours à y répondre. IEnumerable est un comportement tandis que Array est une structure de données (collection contiguë d'éléments de taille fixe, facilitant l'accès aux éléments par des index). Lorsqu'un Array implémente IEnumerable, il est censé représenter également la propriété inhérente IEnumerable (pour faciliter l'itération sur la collection).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.