Inspiré par une autre question concernant la Zip
fonction manquante :
Pourquoi n'y a-t-il pas de ForEach
méthode d'extension dans la Enumerable
classe? Ou n'importe où? La seule classe qui obtient une ForEach
méthode est List<>
. Y a-t-il une raison pour laquelle il manque (performances)?
c#
.net
vb.net
extension-methods
Cameron MacFarland
la source
la source
Parallel.ForEach
pourEnumerable.ForEach
que de retrouver ce dernier n'existe pas. C # a raté une astuce pour rendre les choses faciles ici.Réponses:
Il y a déjà une déclaration foreach incluse dans la langue qui fait le travail la plupart du temps.
Je détesterais voir ce qui suit:
Au lieu de:
Ce dernier est plus clair et plus facile à lire dans la plupart des situations , mais peut-être un peu plus long à taper.
Cependant, je dois admettre que j'ai changé de position sur cette question; une méthode d'extension ForEach () serait en effet utile dans certaines situations.
Voici les principales différences entre l'énoncé et la méthode:
Ce sont tous d'excellents points soulevés par de nombreuses personnes ici et je peux voir pourquoi les gens manquent la fonction. Cela ne me dérangerait pas que Microsoft ajoute une méthode ForEach standard dans la prochaine itération du framework.
la source
foreach
est le type vérifié au moment de la compilation si l'énumérable est paramétré. Il ne manque que la vérification du type de temps de compilation pour les collections non génériques, comme le ferait uneForEach
méthode d'extension hypothétique .col.Where(...).OrderBy(...).ForEach(...)
. Syntaxe beaucoup plus simple, pas de pollution d'écran avec des variables locales redondantes ou des crochets longs dans foreach ().list.ForEach(item => item.DoSomething())
. Et qui dit que c'est une liste? Le cas d'utilisation évident est au bout d'une chaîne; avec l'instruction foreach, vous devrez mettre toute la chaîne aprèsin
, et l'opération à effectuer à l'intérieur du bloc, ce qui est beaucoup moins naturel ou cohérent.La méthode ForEach a été ajoutée avant LINQ. Si vous ajoutez l'extension ForEach, elle ne sera jamais appelée pour les instances List en raison des contraintes des méthodes d'extension. Je pense que la raison pour laquelle il n'a pas été ajouté est de ne pas interférer avec celui qui existe déjà.
Cependant, si vous manquez vraiment cette petite fonction sympa, vous pouvez déployer votre propre version
la source
Vous pouvez écrire cette méthode d'extension:
Avantages
Permet le chaînage:
Les inconvénients
Il ne fera rien tant que vous n'aurez pas forcé l'itération. Pour cette raison, il ne faut pas l'appeler
.ForEach()
. Vous pouvez écrire.ToList()
à la fin, ou vous pouvez également écrire cette méthode d'extension:Cela peut être un écart trop important par rapport aux bibliothèques C # d'expédition; les lecteurs qui ne connaissent pas vos méthodes d'extension ne sauront pas quoi faire de votre code.
la source
{foreach (var e in source) {action(e);} return source;}
numbers.Select(n => n*2);
Select()
dit appliquer une fonction à chaque élément et retourner la valeur de la fonction oùApply()
dit appliquer unAction
à chaque élément et retourner l' élément d' origine .Select(e => { action(e); return e; })
La discussion ici donne la réponse:
Fondamentalement, la décision a été prise de garder les méthodes d'extension fonctionnellement «pures». Un ForEach encouragerait les effets secondaires lors de l'utilisation des méthodes d'extension Enumerable, ce qui n'était pas l'intention.
la source
Bien que je convienne qu'il est préférable d'utiliser la construction intégrée
Exempleforeach
dans la plupart des cas, je trouve que l'utilisation de cette variation sur l'extension ForEach <> est un peu plus agréable que d'avoir à gérerforeach
moi-même l'index de manière régulière :Vous donnerait:
la source
Une solution consiste à écrire
.ToList().ForEach(x => ...)
.avantages
Facile à comprendre - le lecteur a seulement besoin de savoir ce qui est livré avec C #, pas de méthodes d'extension supplémentaires.
Le bruit syntaxique est très doux (ajoute seulement un peu de code extranious).
Cela ne coûte généralement pas de mémoire supplémentaire, car un natif
.ForEach()
devrait de toute façon réaliser la collection entière.les inconvénients
L'ordre des opérations n'est pas idéal. Je préfère réaliser un élément, puis agir en conséquence, puis répéter. Ce code réalise d'abord tous les éléments, puis agit sur chacun d'eux en séquence.
Si la réalisation de la liste lève une exception, vous ne pouvez jamais agir sur un seul élément.
Si l'énumération est infinie (comme les nombres naturels), vous n'avez pas de chance.
la source
Enumerable.ForEach<T>
méthode, il y en a uneList<T>.ForEach
. c) "Ne coûte généralement pas de mémoire supplémentaire, car un .ForEach () natif devrait de toute façon réaliser la collection entière." - un non-sens complet et absolu. Voici l'implémentation d'Enumerable.ForEach <T> que C # fournirait si c'était le cas:public static void ForEach<T>(this IEnumerable<T> list, Action<T> action) { foreach (T item in list) action(item); }
Je me suis toujours demandé cela, c'est pourquoi je porte toujours ça avec moi:
Belle petite méthode d'extension.
la source
Il y a donc eu beaucoup de commentaires sur le fait qu'une méthode d'extension ForEach n'est pas appropriée car elle ne retourne pas une valeur comme les méthodes d'extension LINQ. Bien qu'il s'agisse d'une déclaration factuelle, ce n'est pas entièrement vrai.
Les méthodes d'extension LINQ renvoient toutes une valeur afin qu'elles puissent être chaînées ensemble:
Cependant, ce n'est pas parce que LINQ est implémenté à l'aide de méthodes d'extension que les méthodes d'extension doivent être utilisées de la même manière et renvoyer une valeur. Écrire une méthode d'extension pour exposer une fonctionnalité commune qui ne renvoie pas de valeur est une utilisation parfaitement valide.
L'argument spécifique à propos de ForEach est que, sur la base des contraintes sur les méthodes d'extension (à savoir qu'une méthode d'extension ne remplacera jamais une méthode héritée avec la même signature ), il peut y avoir une situation où la méthode d'extension personnalisée est disponible sur toutes les classes qui se propulsent IEnumerable
<T
> sauf List<T
>. Cela peut être source de confusion lorsque les méthodes commencent à se comporter différemment selon que la méthode d'extension ou la méthode héritée est appelée ou non.la source
Vous pouvez utiliser le (chaînable, mais évalué paresseusement)
Select
, d'abord faire votre opération, puis renvoyer l'identité (ou autre chose si vous préférez)Vous devrez vous assurer qu'il est toujours évalué, soit avec
Count()
(l'opération la moins chère pour énumérer afaik) soit avec une autre opération dont vous aviez besoin de toute façon.Je serais ravi de le voir intégré à la bibliothèque standard:
Le code ci-dessus devient alors
people.WithLazySideEffect(p => Console.WriteLine(p))
ce qui est effectivement équivalent à foreach, mais paresseux et chaînable.la source
Select
ne fait plus ce qu'il est censé faire. c'est certainement une solution pour ce que l'OP demande - mais sur la lisibilité du sujet: personne ne s'attendrait à ce que le select exécute une fonction.Select
ne fait pas ce qu'il est censé faire, c'est un problème avec l'implémentation deSelect
, pas avec le code qui appelleSelect
, qui n'a aucune influence sur ce qui leSelect
fait.Notez que le MoreLINQ NuGet fournit la
ForEach
méthode d'extension que vous recherchez (ainsi qu'unePipe
méthode qui exécute le délégué et donne son résultat). Voir:la source
@Coincoin
La véritable puissance de la méthode d'extension foreach implique la réutilisation de la
Action<>
sans ajouter des méthodes inutiles à votre code. Supposons que vous ayez 10 listes et que vous souhaitiez effectuer la même logique sur elles, et qu'une fonction correspondante ne rentre pas dans votre classe et n'est pas réutilisée. Au lieu d'avoir dix pour les boucles, ou une fonction générique qui est évidemment une aide qui n'appartient pas, vous pouvez garder toute votre logique en un seul endroit (leAction<>
. Donc, des dizaines de lignes sont remplacées paretc...
La logique est au même endroit et vous n'avez pas pollué votre classe.
la source
f(p)
, laissez alors la{ }
pour un raccourci:for (var p in List1.Concat(List2).Concat(List2)) f(p);
.La plupart des méthodes d'extension LINQ renvoient des résultats. ForEach ne rentre pas dans ce modèle car il ne renvoie rien.
la source
public IEnumerable<T> Foreach<T>(this IEnumerable<T> items, Action<T> action) { /* error check */ foreach (var item in items) { action(item); yield return item; } }
Si vous avez F # (qui sera dans la prochaine version de .NET), vous pouvez utiliser
Seq.iter doSomething myIEnumerable
la source
C'est en partie parce que les concepteurs de langage ne sont pas d'accord avec cela d'un point de vue philosophique.
https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/
la source
Vous pouvez utiliser select lorsque vous souhaitez retourner quelque chose. Si vous ne le faites pas, vous pouvez d'abord utiliser ToList, car vous ne voulez probablement pas modifier quoi que ce soit dans la collection.
la source
J'ai écrit un blog à ce sujet: http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx
Vous pouvez voter ici si vous souhaitez voir cette méthode dans .NET 4.0: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093
la source
Dans 3.5, toutes les méthodes d'extension ajoutées à IEnumerable sont là pour la prise en charge de LINQ (notez qu'elles sont définies dans la classe System.Linq.Enumerable). Dans cet article, j'explique pourquoi foreach n'appartient pas à LINQ: méthode d'extension LINQ existante similaire à Parallel.For?
la source
Est-ce moi ou la liste <T> .Foreach a été rendu presque obsolète par Linq. Il y avait à l'origine
où Y devait simplement être IEnumerable (Pre 2.0), et implémenter un GetEnumerator (). Si vous regardez le MSIL généré, vous pouvez voir qu'il est exactement le même que
(Voir http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx pour le MSIL)
Puis, dans DotNet2.0, les génériques sont arrivés et la liste. Foreach m'a toujours semblé être une implémentation du modèle Vistor (voir Design Patterns by Gamma, Helm, Johnson, Vlissides).
Maintenant, bien sûr, en 3.5, nous pouvons plutôt utiliser un Lambda dans le même sens, par exemple, essayez http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh- mon/
la source
Je voudrais développer la réponse d'Aku .
Si vous voulez appeler une méthode dans le seul but de son effet secondaire sans itérer tout l'énumération d'abord, vous pouvez utiliser ceci:
la source
Select(x => { f(x); return x;})
Personne n'a encore souligné que ForEach <T> entraîne une vérification du type de temps de compilation où le mot-clé foreach est vérifié lors de l'exécution.
Après avoir effectué une refactorisation où les deux méthodes ont été utilisées dans le code, je suis favorable à .ForEach, car j'ai dû rechercher les échecs de test / échecs d'exécution pour trouver les problèmes foreach.
la source
foreach
vérification du temps de compilation est moindre. Bien sûr, si votre collection est un IEnumerable non générique, la variable de boucle sera unobject
, mais la même chose serait vraie pour uneForEach
méthode d'extension hypothétique .