Je joue avec C # pour Windows et le développement ASP.net MVC depuis un certain temps maintenant. Mais je ne suis toujours pas clair sur certains points. J'essaie de comprendre la différence fondamentale entre les problèmes de performances et l'utilisation et l'échange de types similaires d' interfaces de collection génériques .
Quelle est la différence fondamentale entre IEnumerable<T>
, ICollection<T>
, List<T>(Class)
?
Je semble les utiliser et les échanger sans voir aucun problème dans mes applications. En outre, existe-t-il des collections génériques plus similaires comme celles-ci qui peuvent être échangées avec ces trois?
c#
generics
interfaces
Pankaj Upadhyay
la source
la source
Réponses:
List <T> est une classe et implémente les interfaces ICollection <T> et IEnumerable <T> . De plus, ICollection <T> étend l'interface IEnumerable <T>. Ils ne sont pas interchangeables, du moins pas à tous points de vue.
Si vous avez un List <T>, vous êtes assuré que cet objet implémente les méthodes et les propriétés requises pour être implémentées par l'interface ICollection <T> et IEnumerable <T>. Le compilateur le sait et vous êtes autorisé à les convertir "vers le bas" en ICollection <T> ou IEnumerable <T> implicitement. Cependant, si vous avez un ICollection <T>, vous devez d'abord vérifier explicitement dans votre code s'il s'agit d'un List <T> ou autre chose, peut-être un Dictionary <T> (où T est un KeyValuePair ) avant de le convertir en ce que vous le désir.
Vous savez que ICollection étend IEnumerable, vous pouvez donc le convertir en un IEnumerable. Mais si vous n'avez qu'un IEnumerable, encore une fois, vous n'êtes pas assuré qu'il s'agit d'une liste. C'est possible, mais ça pourrait être autre chose. Vous devez vous attendre à une exception de transtypage non valide si vous tentez de transtyper une liste <T> en un dictionnaire <T> par exemple.
Ils ne sont donc pas "interchangeables".
En outre, il existe de nombreuses interfaces génériques, vérifiez ce que vous pouvez trouver dans l' espace de noms System.Collections.Generic .
Edit: concernant votre commentaire, il n'y a absolument aucune pénalité de performance si vous utilisez List <T> ou l'une des interfaces qu'il implémente. Vous devrez toujours créer un nouvel objet, consultez le code suivant:
list , myColl et myEnum pointent tous vers le même objet. Que vous le déclariez comme une liste ou une ICollection ou un IEnumerable, je demande toujours au programme de créer une liste. J'aurais pu écrire ceci:
myColl , lors de l'exécution est toujours une liste.
Cependant , c'est le point le plus important ... pour réduire le couplage et augmenter la maintenabilité, vous devez toujours déclarer vos variables et paramètres de méthode en utilisant le plus petit dénominateur possible pour vous, qu'il s'agisse d'une interface ou d'une classe abstraite ou concrète.
Imaginez que la seule chose dont la méthode "PerformOperation" ait besoin est d'énumérer les éléments, de faire un peu de travail et de quitter, dans ce cas vous n'avez pas besoin des centaines de méthodes supplémentaires disponibles dans List <T>, vous avez seulement besoin de ce qui est disponible dans IEnumerable <T >, les règles suivantes devraient donc s'appliquer:
Ce faisant, vous et les autres développeurs savez que tout objet d'une classe implémentant l'interface IEnumerable <T> peut être attribué à cette méthode. Il peut s'agir d'une liste, d'un dictionnaire ou d'une classe de collection personnalisée écrite par un autre développeur.
Si au contraire vous spécifiez que vous avez explicitement besoin d'une liste concrète <T> (et bien que ce soit rarement le cas dans la vie réelle, cela peut toujours arriver), vous et les autres développeurs savez qu'il doit s'agir d'une liste ou d'une autre classe concrète héritant de la liste.
la source
IList
plutôt queList
dans la déclaration de méthode.List<>
fonctionnalités spécifiques, comme.AddRange()
. LeIList<>
n'expose pas cela.Jetez un œil aux pages MSDN pour ICollection et IEnumerable .
En termes très abstraits, c'est ainsi que je conçois ces types.
Un IEnumerable est tout ce qui peut être énuméré - c'est-à-dire, itéré sur. Cela ne signifie pas nécessairement une «collection»; par exemple, un IQueryable implémente IEnumerable et ce n'est pas une collection, mais c'est quelque chose qui peut être interrogé pour renvoyer des objets. Pour implémenter IEnumerable, un objet doit uniquement pouvoir renvoyer un objet lorsqu'il est interrogé. Je pourrais dire que j'ai un énumérable de tâches que je vais faire aujourd'hui (ce n'est pas une liste parce que je ne l'ai pas écrite ou formulée, mais je pourrais vous dire ce que je vais faire maintenant, et si vous demandiez «et ensuite?», je serais en mesure de vous dire la tâche suivante).
Un ICollection est plus concret qu'un IEnumerable. Une différence clé est qu'une collection sait combien d'éléments elle contient; pour déterminer le nombre d'éléments dans un énumérable, vous effectuez une boucle efficace et les comptez:
Une collection est généralement quelque chose qui sait déjà où se trouvent tous ses éléments, et n'aura pas à aller les trouver ou les générer lorsque vous les demanderez. C'est plus ... concret qu'un énumérable.
À mon avis, la différence entre un énumérable et une collection est beaucoup plus grande que la différence entre une collection et une liste. En fait, j'ai du mal à penser à une différence pratique entre une collection et une liste, mais je pense que la liste fournit de meilleures méthodes de recherche et de commande.
Les autres types de Collection incluent
Queue
etStack
, ainsi queDictionary
.Les noms de ces types sont très utiles - vous pouvez concevoir une file d'attente et une pile comme leurs homologues du monde réel, et considérer les différences que vous pourriez avoir avec une liste.
la source
List
est unICollection
, mais unICollection
est pas toujoursList
(Queue
,Stack
,Dictionary
, ...)Queue<int> queue = (Queue<int>)list;
lancera unInvalidCastException
quandlist
n'est pas unQueue<int>
. La différence entre la file d'attente et la liste est hors de portée pour cette question.IQueryable:
la requête n'est exécutée que pour vraiment itérer sur les éléments, peut-être en faisant un .ToList ()
IEnumerable:
liste d'éléments uniquement en avant. Vous ne pouvez pas accéder à "l'élément 4" sans passer les éléments 0-3. liste en lecture seule, vous ne pouvez pas y ajouter ou en supprimer. Peut encore utiliser l'exécution différée.
IList:
l'accès aléatoire à la liste complète entièrement en mémoire prend en charge l'ajout et la suppression
ICollection:
Est entre IEnumerable et IList. Ce qui est "le meilleur" dépend de vos besoins. Habituellement, bien qu'un IEnumerable soit "assez bon" si vous ne souhaitez afficher que des éléments. Utilisez au moins toujours la variante générique.
la source