Je voudrais faire l'équivalent de ce qui suit dans LINQ, mais je ne peux pas comprendre comment:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
Quelle est la vraie syntaxe?
linq
foreach
ienumerable
tags2k
la source
la source
ForEach()
.ForEach
extension .foreach (var i in items) i.Dostuff();
Réponses:
Il n'y a pas d'extension ForEach pour
IEnumerable
; seulement pourList<T>
. Donc tu pourrais faireSinon, écrivez votre propre méthode d'extension ForEach:
la source
IENumerable<T>
dans la méthode d'extension. Comme:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Fredrik a fourni le correctif, mais il vaut peut-être la peine de se demander pourquoi ce n'est pas dans le cadre pour commencer. Je crois que l'idée est que les opérateurs de requête LINQ devraient être sans effet secondaire, s'inscrivant dans une manière raisonnablement fonctionnelle de regarder le monde. Clairement, ForEach est exactement le contraire - une construction purement basée sur les effets secondaires.
Cela ne veut pas dire que c'est une mauvaise chose à faire - il suffit de penser aux raisons philosophiques derrière la décision.
la source
Seq.iter
ne renvoie rien, encore moins une nouvelle séquence avec des éléments à effets secondaires. Il s'agit vraiment d'effets secondaires. Vous pensez peut-êtreSeq.map
, carSeq.iter
est exactement équivalent à uneForEach
méthode d'extension activéeIEnumerabe<_>
.Mise à jour 17/07/2012: Apparemment à partir de C # 5.0, le comportement de
foreach
décrit ci-dessous a été modifié et « l'utilisation d'uneforeach
variable d'itération dans une expression lambda imbriquée ne produit plus de résultats inattendus. » Cette réponse ne s'applique pas à C # ≥ 5.0 .@John Skeet et tous ceux qui préfèrent le mot-clé foreach.
Le problème avec "foreach" en C # avant 5.0 , c'est qu'il est incompatible avec le fonctionnement de l'équivalent "pour la compréhension" dans d'autres langues, et avec la façon dont je m'attendrais à ce qu'il fonctionne (opinion personnelle indiquée ici uniquement parce que d'autres ont mentionné leur opinion sur la lisibilité). Voir toutes les questions concernant " Accès à la fermeture modifiée " ainsi que " Fermeture sur la variable de boucle considérée comme nuisible ". Ceci n'est "nuisible" qu'en raison de la façon dont "foreach" est implémenté en C #.
Prenez les exemples suivants en utilisant la méthode d'extension fonctionnellement équivalente à celle de la réponse de @Fredrik Kalseth.
Toutes mes excuses pour l'exemple trop artificiel. J'utilise uniquement Observable parce que ce n'est pas totalement exagéré de faire quelque chose comme ça. Évidemment, il existe de meilleures façons de créer cet observable, j'essaie seulement de démontrer un point. En règle générale, le code souscrit à l'observable est exécuté de manière asynchrone et potentiellement dans un autre thread. Si vous utilisez "foreach", cela pourrait produire des résultats très étranges et potentiellement non déterministes.
Le test suivant utilisant la méthode d'extension "ForEach" réussit:
Ce qui suit échoue avec l'erreur:
Attendu: équivalent à <0, 1, 2, 3, 4, 5, 6, 7, 8, 9> Mais était: <9, 9, 9, 9, 9, 9, 9, 9, 9, 9>
la source
Vous pouvez utiliser l'
FirstOrDefault()
extension, qui est disponible pourIEnumerable<T>
. En revenantfalse
du prédicat, il sera exécuté pour chaque élément mais ne se souciera pas qu'il ne trouve pas réellement de correspondance. Cela évitera lesToList()
frais généraux.la source
foreach(Item i in GetItems()) { i.DoStuff();}
vous, vous avez pris plus de personnages et rendu extrêmement confusitems.All(i => { i.DoStuff(); return true; }
J'ai pris la méthode de Fredrik et modifié le type de retour.
De cette façon, la méthode prend en charge l' exécution différée comme les autres méthodes LINQ.
EDIT: Si cela n'était pas clair, toute utilisation de cette méthode doit se terminer par ToList () ou toute autre façon de forcer la méthode à travailler sur l'énumérable complet. Sinon, l'action ne serait pas effectuée!
Et voici le test pour vous aider à le voir:
Si vous supprimez la ToList () à la fin, vous verrez le test échouer puisque le StringBuilder contient une chaîne vide. En effet, aucune méthode n'a forcé ForEach à énumérer.
la source
ForEach
est intéressante, mais elle ne correspond pas au comportement deList.ForEach
, dont la signature estpublic void ForEach(Action<T> action)
. Il ne correspond pas non plus au comportement de l'Observable.ForEach
extension àIObservable<T>
, dont la signature estpublic static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)
. FWIW, l'ForEach
équivalent des collections Scala, même celles qui sont paresseuses, a également un type de retour qui équivaut à void en C #.Select
avecToList
. Le butForEach
est de ne pas avoir à appelerToList
. Il devrait s'exécuter immédiatement.Gardez vos effets secondaires hors de mon IEnumerable
Comme d'autres l'ont souligné ici et à l'étranger, LINQ et les
IEnumerable
méthodes devraient être exemptes d'effets secondaires.Voulez-vous vraiment "faire quelque chose" pour chaque élément de l'IEnumerable? C'est alors
foreach
le meilleur choix. Les gens ne sont pas surpris lorsque des effets secondaires se produisent ici.Je parie que tu ne veux pas d'effets secondaires
Cependant, d'après mon expérience, les effets secondaires ne sont généralement pas nécessaires. Le plus souvent, il y a une simple requête LINQ à découvrir, accompagnée d'une réponse StackOverflow.com de Jon Skeet, Eric Lippert ou Marc Gravell expliquant comment faire ce que vous voulez!
Quelques exemples
Si vous êtes en train d'agréger (d'accumuler) une certaine valeur, vous devriez envisager la
Aggregate
méthode d'extension.Vous souhaitez peut-être en créer un nouveau à
IEnumerable
partir des valeurs existantes.Ou peut-être souhaitez-vous créer une table de correspondance:
La liste (jeu de mots pas entièrement destiné) de possibilités s'allonge encore et encore.
la source
Si vous voulez agir comme rouleaux d'énumération, vous devez rapporter chaque élément.
la source
Il existe une version expérimentale par Microsoft des extensions interactives à LINQ (également sur NuGet , voir le profil de RxTeams pour plus de liens). La vidéo de Channel 9 l' explique bien.
Ses documents sont uniquement fournis au format XML. J'ai exécuté cette documentation à Sandcastle pour lui permettre d'être dans un format plus lisible. Décompressez l'archive des documents et recherchez index.html .
Parmi de nombreux autres avantages, il fournit l'implémentation ForEach attendue. Il vous permet d'écrire du code comme ceci:
la source
Selon PLINQ (disponible depuis .Net 4.0), vous pouvez faire un
faire une boucle foreach parallèle sur un IEnumerable.
la source
Le but de ForEach est de provoquer des effets secondaires. IEnumerable sert à l'énumération paresseuse d'un ensemble.
Cette différence conceptuelle est bien visible quand on y réfléchit.
SomeEnumerable.ForEach(item=>DataStore.Synchronize(item));
Cela ne s'exécutera pas jusqu'à ce que vous fassiez un "count" ou un "ToList ()" ou quelque chose dessus. Ce n'est clairement pas ce qui est exprimé.
Vous devez utiliser les extensions IEnumerable pour configurer des chaînes d'itération, définissant le contenu par leurs sources et conditions respectives. Les arbres d'expression sont puissants et efficaces, mais vous devez apprendre à apprécier leur nature. Et pas seulement pour la programmation autour d'eux afin de sauvegarder quelques caractères remplaçant l'évaluation paresseuse.
la source
Beaucoup de gens l'ont mentionné, mais j'ai dû l'écrire. N'est-ce pas le plus clair / le plus lisible?
Court et simple (st).
la source
GetItems()
méthode retourne.foreach (var item in GetItems()) item.DoStuff();
c'est juste une beauté.Maintenant, nous avons la possibilité de ...
Bien sûr, cela ouvre une toute nouvelle boîte de ténias.
ps (Désolé pour les polices, c'est ce que le système a décidé)
la source
Comme de nombreuses réponses le soulignent déjà, vous pouvez facilement ajouter vous-même une telle méthode d'extension. Cependant, si vous ne voulez pas faire cela, bien que je ne sois pas au courant de quelque chose comme ça dans la BCL, il y a toujours une option dans l'
System
espace de noms, si vous avez déjà une référence à Reactive Extension (et si vous ne le faites pas , tu aurais dû):Bien que les noms de méthode soient un peu différents, le résultat final est exactement ce que vous recherchez.
la source
ForEach peut également être enchaîné , il suffit de le remettre sur le pileline après l'action. rester fluide
Une version d'implémentation désireuse .
Edit: une version Lazy utilise return return, comme ceci .
La version Lazy a besoin d'être matérialisée, ToList () par exemple, sinon, rien ne se passe. voir ci-dessous d'excellents commentaires de ToolmakerSteve.
Je garde à la fois ForEach () et ForEachLazy () dans ma bibliothèque.
la source
foreach(T item in enu) {action(item); yield return item;}
foreach (T item in enu) { action1(item); action2(item); action3(item); }
? Une boucle unique et explicite. Je suppose que s'il était important de faire toutes les actions1 AVANT de commencer à faire les actions2.ProcessShipping()
? Vous envoyez un e-mail à l'acheteur, chargez sa carte de crédit, mais ne lui envoyez jamais ses affaires? Certainement demander des problèmes.Cette abstraction "d'approche fonctionnelle" fuit beaucoup. Rien au niveau de la langue n'empêche les effets secondaires. Tant que vous pouvez le faire appeler votre lambda / délégué pour chaque élément du conteneur - vous obtiendrez le comportement "ForEach".
Voici par exemple une façon de fusionner srcDictionary en destDictionary (si la clé existe déjà - écrase)
c'est un hack, et ne doit être utilisé dans aucun code de production.
la source
foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }
? Si ce n'est pas dans le code de production, où et pourquoi devriez-vous jamais l'utiliser?Inspiré par Jon Skeet, j'ai étendu sa solution avec les éléments suivants:
Méthode d'extension:
Client:
. . .
la source
MoreLinq a
IEnumerable<T>.ForEach
et une tonne d'autres extensions utiles. Cela ne vaut probablement pas la peine de prendre la dépendance uniquementForEach
, mais il y a beaucoup de choses utiles là-dedans.https://www.nuget.org/packages/morelinq/
https://github.com/morelinq/MoreLINQ
la source
Je suis en désaccord avec la notion selon laquelle les méthodes d'extension de lien devraient être sans effet secondaire (non seulement parce qu'elles ne le sont pas, tout délégué peut effectuer des effets secondaires).
Considérer ce qui suit:
Ce que l'exemple montre est vraiment juste une sorte de liaison tardive qui permet d'invoquer l'une des nombreuses actions possibles ayant des effets secondaires sur une séquence d'éléments, sans avoir à écrire une construction de gros commutateur pour décoder la valeur qui définit l'action et traduire dans sa méthode correspondante.
la source
Pour rester fluide, on peut utiliser une telle astuce:
la source
Pour VB.NET, vous devez utiliser:
la source
List
ouIList
. Pour un généralIEnumerable
, écrivez l'équivalent VB de la méthode d'extension ForEach de la réponse acceptée .Encore un autre
ForEach
exemplela source