J'ai des doutes sur le fonctionnement des énumérateurs et LINQ. Considérez ces deux sélections simples:
List<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct().ToList();
ou
IEnumerable<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct();
J'ai changé les noms de mes objets d'origine pour que cela ressemble à un exemple plus générique. La requête elle-même n'est pas si importante. Ce que je veux demander, c'est ceci:
foreach (Animal animal in sel) { /*do stuff*/ }
J'ai remarqué que si j'utilise
IEnumerable
, quand je débogue et inspecte "sel", qui dans ce cas est l'IEnumerable, il a des membres intéressants: "inner", "external", "innerKeySelector" et "externalKeySelector", ces 2 derniers apparaissent être délégués. Le membre "intérieur" ne contient pas d'instances "Animal", mais plutôt des instances "Espèce", ce qui était très étrange pour moi. Le membre "externe" contient des instances "Animal". Je suppose que les deux délégués déterminent ce qui entre et ce qui en sort?J'ai remarqué que si j'utilise "Distinct", le "intérieur" contient 6 éléments (c'est incorrect car seulement 2 sont distincts), mais le "extérieur" contient les valeurs correctes. Encore une fois, les méthodes déléguées déterminent probablement cela, mais c'est un peu plus que ce que je sais sur IEnumerable.
Plus important encore, laquelle des deux options est la meilleure en termes de performances?
La conversion de liste mal via .ToList()
?
Ou peut-être utiliser directement l'énumérateur?
Si vous le pouvez, veuillez également expliquer un peu ou lancer des liens qui expliquent cette utilisation de IEnumerable.
la source
IEnumerable<T>
sera LINQ-To-Objects après la première partie, ce qui signifie que tout repéré devra être retourné pour exécuter Feline. D'un autre côté, unIQuertable<T>
permettra à la requête d'être affinée, en tirant uniquement sur les félins repérés.Il y a un très bon article écrit par: TechBlog de Claudio Bernasconi ici: Quand utiliser IEnumerable, ICollection, IList et List
Voici quelques points de base sur les scénarios et les fonctions:
la source
List
est une mise en œuvreIList
et en tant que telle a des fonctionnalités supplémentaires au - dessus de ceuxIList
(par exempleSort
,Find
,InsertRange
). Si vous vous forcez à utiliserIList
plusList
, vous perdez ces méthodes dont vous pourriez avoir besoinIReadOnlyCollection<T>
[]
ici un tableau simple .Une classe qui implémente
IEnumerable
vous permet d'utiliser laforeach
syntaxe.Fondamentalement, il a une méthode pour obtenir l'élément suivant dans la collection. Il n'a pas besoin que toute la collection soit en mémoire et ne sait pas combien d'éléments il
foreach
contient , continue à obtenir l'élément suivant jusqu'à épuisement.Cela peut être très utile dans certaines circonstances, par exemple dans une table de base de données massive, vous ne voulez pas copier le tout dans la mémoire avant de commencer à traiter les lignes.
maintenant
List
outilsIEnumerable
, mais représente toute la collection en mémoire. Si vous en avez unIEnumerable
et que vous appelez,.ToList()
vous créez une nouvelle liste avec le contenu de l'énumération en mémoire.Votre expression linq renvoie une énumération et, par défaut, l'expression s'exécute lorsque vous parcourez à l'aide de
foreach
. UneIEnumerable
instruction linq s'exécute lorsque vous itérez leforeach
, mais vous pouvez la forcer à itérer plus tôt en utilisant.ToList()
.Voici ce que je veux dire:
la source
foreach
tandis que List ira par exemple index. Maintenant, si je voudrais connaître le nombre / la longueur d'thing
avance, IEnumerable n'aidera pas, non?List
etArray
mettre en œuvreIEnumerable
. Vous pouvez considérerIEnumerable
comme le plus petit dénominateur commun qui fonctionne à la fois dans les collections de mémoire et les grandes qui obtiennent un élément à la fois. Lorsque vous appelez,IEnumerable.Count()
vous pouvez appeler une.Length
propriété rapide ou parcourir toute la collection - le fait est queIEnumerable
vous ne savez pas. Cela peut être un problème, mais si vous y allez,foreach
vous ne vous en souciez pas - votre code fonctionnera avec unArray
ouDataReader
le même.Personne n'a mentionné une différence cruciale, ironiquement, a répondu à une question fermée en double.
Voir Différence pratique entre List et IEnumerable
la source
La chose la plus importante à réaliser est que, en utilisant Linq, la requête n'est pas évaluée immédiatement. Il n'est exécuté que dans le cadre d'une itération à travers le résultat
IEnumerable<T>
en unforeach
- c'est ce que font tous les délégués étranges.Ainsi, le premier exemple évalue la requête immédiatement en appelant
ToList
et en plaçant les résultats de la requête dans une liste.Le deuxième exemple renvoie un
IEnumerable<T>
qui contient toutes les informations nécessaires pour exécuter la requête ultérieurement.En termes de performances, la réponse est que cela dépend . Si vous avez besoin que les résultats soient évalués à la fois (par exemple, vous mutez les structures que vous interrogez plus tard, ou si vous ne voulez pas que l'itération sur la
IEnumerable<T>
prenne trop de temps), utilisez une liste. Sinon, utilisez unIEnumerable<T>
. La valeur par défaut doit être d'utiliser l'évaluation à la demande dans le deuxième exemple, car elle utilise généralement moins de mémoire, sauf s'il existe une raison spécifique pour stocker les résultats dans une liste.la source
Join
faire, c'est le travail - intérieur et extérieur sont les deux côtés de la jointure. En règle générale, ne vous inquiétez pas de ce qui se trouve réellement dans leIEnumerables
, car il sera complètement différent de votre code actuel. Ne vous inquiétez que de la sortie réelle lorsque vous itérez dessus :)L'avantage de IEnumerable est l'exécution différée (généralement avec des bases de données). La requête ne sera pas exécutée tant que vous n'aurez pas parcouru les données. C'est une requête en attente jusqu'à ce qu'elle soit nécessaire (aka chargement paresseux).
Si vous appelez ToList, la requête sera exécutée ou "matérialisée" comme j'aime à le dire.
Il y a des avantages et des inconvénients pour les deux. Si vous appelez ToList, vous pouvez supprimer un mystère quant au moment où la requête est exécutée. Si vous vous en tenez à IEnumerable, vous obtenez l'avantage que le programme ne fait aucun travail jusqu'à ce qu'il soit réellement requis.
la source
Je vais partager un concept mal utilisé dans lequel je suis tombé un jour:
Résultat attendu
Résultat actuel
Explication
Comme pour les autres réponses, l'évaluation du résultat a été différée jusqu'à l'appel
ToList
ou des méthodes d'invocation similaires, par exempleToArray
.Je peux donc réécrire le code dans ce cas comme:
Jouez autour
https://repl.it/E8Ki/0
la source
IEnumerable
marche, mais maintenant ce n'est plus puisque je sais comment;)Si tout ce que vous voulez faire est de les énumérer, utilisez le
IEnumerable
.Attention, cependant, changer la collection d'origine en cours d'énumération est une opération dangereuse - dans ce cas, vous voudrez d'
ToList
abord. Cela créera un nouvel élément de liste pour chaque élément en mémoire, énumérant leIEnumerable
et est donc moins performant si vous ne l'énumérez qu'une seule fois - mais plus sûr et parfois lesList
méthodes sont pratiques (par exemple en accès aléatoire).la source
IEnumerable
, puis en créant d'abord une liste (et en itérant dessus), vous devez itérer sur les éléments deux fois . Donc, à moins que vous ne souhaitiez effectuer des opérations plus efficaces sur la liste, cela signifie vraiment une baisse des performances..ToList()
ça aide ici;)En plus de toutes les réponses affichées ci-dessus, voici mes deux cents. Il existe de nombreux autres types que List qui implémente IEnumerable comme ICollection, ArrayList etc. Donc, si nous avons IEnumerable comme paramètre d'une méthode, nous pouvons transmettre n'importe quel type de collection à la fonction. C'est-à-dire que nous pouvons avoir une méthode pour opérer sur l'abstraction et non sur une implémentation spécifique.
la source
Il existe de nombreux cas (comme une liste infinie ou une très grande liste) où IEnumerable ne peut pas être transformé en liste. Les exemples les plus évidents sont tous les nombres premiers, tous les utilisateurs de facebook avec leurs détails ou tous les articles sur ebay.
La différence est que les objets "List" sont stockés "ici et maintenant", alors que les "objets IEnumerable" fonctionnent "un par un". Donc, si je passe en revue tous les éléments sur ebay, un par un serait quelque chose que même un petit ordinateur peut gérer, mais ".ToList ()" me manquerait sûrement de mémoire, quelle que soit la taille de mon ordinateur. Aucun ordinateur ne peut à lui seul contenir et gérer une telle quantité de données.
[Modifier] - Inutile de dire que ce n'est pas "ni ceci ni cela". il serait souvent judicieux d'utiliser à la fois une liste et un IEnumerable dans la même classe. Aucun ordinateur au monde ne pourrait répertorier tous les nombres premiers, car par définition cela nécessiterait une quantité infinie de mémoire. Mais vous pourriez facilement penser à un
class PrimeContainer
qui contient unIEnumerable<long> primes
, qui, pour des raisons évidentes, contient également unSortedList<long> _primes
. tous les nombres premiers calculés jusqu'à présent. le prochain nombre premier à vérifier ne serait exécuté que par rapport aux nombres premiers existants (jusqu'à la racine carrée). De cette façon, vous obtenez les deux - les nombres premiers un à la fois (IEnumerable) et une bonne liste de "nombres premiers jusqu'à présent", ce qui est une assez bonne approximation de la liste entière (infinie).la source