Quel est le rôle de IEnumerable & lt; T & gt; et pourquoi devrais-je l'utiliser?
Pourquoi devrais-je utiliser IEnumerable<T>
quand je peux faire avec...dire List<T>
? Quel est l'avantage de l'ancien cours de la dernière?
source d'informationauteur Deepanjan Nag
Vous devez vous connecter pour publier un commentaire.
IEnumerable<T>
est une interface qui nous dit que nous pouvons énumérer sur une séquence deT
instances. Si vous avez besoin de permettre à quelqu'un de voir et d'effectuer une action pour chaque objet dans une collection, c'est suffisant.List<T>
d'autre part, est une mise en œuvre spécifique deIEnumerable<T>
qui stocke les objets dans un spécifiques, connus. En interne, cela peut être une très bonne façon de stocker vos valeurs que vous exposez viaIEnumerable<T>
mais unList<T>
n'est pas toujours approprié. Par exemple, si vous n'avez pas besoin d'accéder aux éléments par index, mais constamment de les insérer au début de votre collection et puis supprimer des éléments à partir de la fin, unQueue<T>
serait beaucoup plus approprié de les utiliser.En utilisant
IEnumerable<T>
dans votre API, vous donnez vous-même la possibilité de changer la mise en œuvre interne à tout moment sans aucune autre modification du code. Cela a d'énormes avantages en termes de permettre à votre code pour être flexible et facile à entretenir.Sur ce point Jeffrey-Richter écrit:
Lors de la déclaration de la méthode des types de paramètres, vous devez spécifier le plus faible possible,
préférant les interfaces sur les classes de base. Par exemple, si vous écrivez une méthode qui
manipule une collection d'éléments, il serait préférable de déclarer la méthode du paramètre par
à l'aide d'une interface telle que
IEnumerable<T>
plutôt que d'utiliser un solide de type de données telles queList<T>
ou même une forte type d'interface tels queICollection<T>
ouIList<T>
:La raison, bien sûr, c'est que quelqu'un peut appeler la première méthode de passage dans un tableau d'objet, un
List<T>
objet, unString
objet, et ainsi de suite — tout objet dont le type implémenteIEnumerable<T>
. La seconde méthode permet seulementList<T>
objets à être passé; il n'accepte un tableau ou unString
objet. Évidemment, la première méthode est préférable car il est plus souple et peut être utilisé dans un éventail beaucoup plus large de scénarios.Naturellement, si vous écrivez une méthode qui nécessite une liste (pas n'importe quel objet énumérable), vous devez déclarer le type de paramètre comme un
IList<T>
. Vous devriez toujours éviter de déclarer le type de paramètre queList<T>
. À l'aide deIList<T>
permet à l'appelant de passer des tableaux et d'autres objets dont le type implémenteIList<T>
.Sur le revers de la médaille, il est généralement préférable de déclarer une méthode de type de retour en utilisant le plus fort possible (en essayant de ne pas vous engager à un type spécifique).
Différentes implémentations de collections peuvent être énumérable; à l'aide de IEnumerable il est clair que ce qui vous intéresse est le enumerability, et non pas à la structure du sous-jacent de la mise en œuvre de la collection.
Comme l'a mentionné M. Copsey, ce qui a l'avantage d'assurer le découplage de la mise en œuvre, mais je suis de l'opinion que d'une définition claire du plus petit sous-ensemble de la fonctionnalité d'interface que possible (c'est à dire, à l'aide de IEnumerable au lieu de la Liste si possible) fournit exactement que le découplage tout en exigeant une bonne philosophie de conception. C'est-à-dire, vous pouvez réaliser le découplage, mais pas de réduire la dépendance, mais vous ne pouvez pas réduire la dépendance sans la réalisation maximale de découplage.
En utilisant le concept de itérateurs vous pouvez obtenir une amélioration majeure de l'algorithme de la qualité, à la fois en termes de vitesse et l'utilisation de la mémoire.
Considérons les deux exemples de code suivants. À la fois analyser le fichier, on stocke les lignes de la collecte, les autres utilisations énumérable.
Premier exemple prend C * O(N) le temps et la mémoire O(N)
Deuxième exemple prend 1/2 C * O(N) le temps et la mémoire constante.
Voici le code de SelectLines()
Ici, c'est pourquoi 1/2 de temps. Disons que la probabilité de trouver l'élément à n'importe quelle position dans la gamme des fichiers est la même. En cas de IEnumerable, seules les lignes jusqu'à l'élément d'intérêt sera lu à partir du fichier. En cas de ToList appel au cours de la énumérable, tous les fichiers seront lus.
Bien sûr, la Liste contiendra tous les éléments en mémoire, c'est pourquoi O(N) l'utilisation de la mémoire.
Si vous envisagez de faire construire une API publique, il est préférable d'utiliser
IEnumerable
queList<T>
parce que vous feriez mieux d'utiliser le plus minimaliste/l'interface de la classe.List<T>
vous permet d'accéder à des objets par l'indice si c'est nécessaire.Ici est une assez bonne ligne de conduite pour l'utilisation
IEnumerable
ICollection
List<T>
et ainsi de suite.Généralement vous n'utilisez pas
IEunumerable
directement. C'est la classe de base pour un certain nombre d'autres collections que vous êtes plus susceptibles d'utiliser.IEnumerable
par exemple, offre la possibilité de boucle à travers une collection avecforeach
. Qui est utilisé par de nombreux héritant des classes commeList<T>
. MaisIEnumerable
n'offre pas une méthode de tri (bien que vous pouvez utiliser Linq pour cela), alors que certaines autres génériques collections commeList<T>
à avoir cette méthode.Oh, bien sûr, vous pouvez l'utiliser pour créer vos propres types de collection. Mais pour des trucs tous les jours, il n'est probablement pas utile que les collections qui en découlent.
IEnumerable vous donne la façon de mettre en œuvre votre propre logique de stockage et d'une itération sur l'objet de la collecte
Pourquoi mettre en place IEnumerable dans votre classe?
Si vous écrivez une classe, et la classe implémente l'interface IEnumerable (générique (T) ou non), vous êtes en permettant à tout consommateur de votre classe à parcourir sa collection sans savoir comment il est structuré.
Une LinkedList est mis en œuvre différemment d'une File d'attente, une Pile, un BinaryTree, une table de hachage, Graphique, etc. La collection représentée par votre classe pourrait être structuré de différentes façons.
Comme un "consommateur" (si vous écrivez une classe, et la classe consomme/fait usage d'une classe-objet qui implémente l'interface IEnumerable) vous pouvez l'utiliser sans se préoccuper de comment il est mis en œuvre. Parfois, les consommateurs de la classe ne se soucie pas de la mise en œuvre - il veut juste aller sur tous les éléments (impression? les changer? les comparer? etc.)
(Donc en tant que consommateur, si votre objectif est de parcourir tous les éléments dans un BinaryTree classe, et vous avez sauté cette leçon de Données-Structures-101 - si le BinaryTree codeur mise en œuvre de la IEnumberable - vous avez de la chance! Vous n'avez pas à ouvrir un livre et apprenez comment parcourir l'arbre - mais tout simplement utiliser l'instruction foreach sur cet objet et vous avez terminé.)
Comme un "producteur" (l'écriture d'une classe qui contient la structure des données/de la collection), vous pourriez ne pas vouloir les consommateurs de votre classe pour gérer la façon dont il est structuré (peur qu'ils pourraient casser, peut-être). Vous pouvez faire la collection privée, et seulement exposer un public IEnumerator.
Il peut aussi permettre une certaine uniformité, une collection peut avoir un peu de moyens pour effectuer une itération sur les éléments (Précommande, Afinde, PostOrder, Largeur, Profondeur du Premier, etc.) - mais il n'y a qu'1 de la mise en œuvre de IEnumerable. Vous pouvez utiliser cette fonction pour définir le "par défaut" afin de parcourir la collection.
Pourquoi utiliser IEnumerable dans votre méthode?
Si j'écris une méthode qui prend une collection, itère sur elle, et prend des mesures sur les éléments (les agréger? compare? etc.) pourquoi devrais-je me limiter à 1 type de collections?
L'écriture de cette méthode
public void Sum(List<int> list) {...}
de la somme de tous les éléments de la collection, les moyens, je ne peut recevoir une liste et une somme de plus de. L'écriture de cepublic void Sum(IEnumerable<int> collection) {...}
signifie que je peux prendre n'importe quel objet qui implémente IEnumberable (Listes, Files, Piles, etc.) et la somme de tous leurs éléments.D'Autres Considérations
Il y a aussi les questions de l'exécution différée et des ressources non managées. IEnumerable faut utiliser du rendement de la syntaxe, ce qui signifie que vous passez sur chaque élément par lui-même et peut effectuer toutes sortes de calculs avant et après. Et encore une fois, cela se passe un par un, de sorte que vous n'avez pas à tenir toute la collection lorsque vous démarrez. Les calculs ne sera pas réellement être effectué jusqu'à ce que l'énumération commence (c'est à dire jusqu'à l'exécution de la boucle foreach). Et qui pourrait être utile et plus efficace dans certains cas. Par exemple, votre classe pourrait ne pas tenir toute la collection dans la mémoire, mais plutôt itérer sur tous les fichiers existant dans un certain répertoire, ou des éléments de certaines DB, ou d'autres ressources non managées. IEnumerable peut intervenir et de le faire pour vous (vous pouvez aussi le faire sans IEnumerable, mais IEnumberable "s'adapte" sur le plan conceptuel, plus il vous donne l'avantage de pouvoir utiliser l'objet produit dans une boucle foreach).
Mise en œuvre de IEnumerable<T> est généralement la meilleure façon pour les élèves d'une classe pour indiquer qu'il doit être utilisable avec un "foreach" en boucle, et que plusieurs "foreach" les boucles sur le même objet doivent fonctionner de façon indépendante. Bien qu'il existe des utilisations de IEnumerable<T> autre que "foreach", l'indication normale que l'on doit mettre en œuvre IEnumerable est que la classe est un endroit où il serait plus logique de dire "foreach foo dans classItem {foo.faire_quelque_chose();}.
IEnumerable de prendre avantage de l'exécution différée, comme expliqué ici: IEnumerable vs la Liste de Ce qu'il faut Utiliser? Comment fonctionnent-ils?
IEnumerable activer la référence implicite de conversion pour les types de tableau qui connu comme la Covariance. Considérons l'exemple suivant:
public abstract class Véhicule
{
}