Question

J'ai un Enumerable<T> et je cherche une méthode qui me permet d'exécuter une action pour chaque élément, un peu comme Select mais pour les effets secondaires. Quelque chose comme:

string[] Names = ...;
Names.each(s => Console.Writeline(s));

ou

Names.each(s => GenHTMLOutput(s));   
// (where GenHTMLOutput cannot for some reason receive the enumerable itself as a parameter)

J'ai essayé Select(s=> { Console.WriteLine(s); return s; }), mais il n'a pas quoi que ce soit l'impression.

Était-ce utile?

La solution

Une façon rapide et facile à obtenir c'est:

Names.ToList().ForEach(e => ...);

Autres conseils

Vous cherchez foreach toujours insaisissable qui existe actuellement que sur la liste de collection générique. Il y a beaucoup de discussions en ligne à savoir si Microsoft doit ou non ajouter cela comme une méthode LINQ. , Vous avez actuellement à rouler votre propre:

public static void ForEach<T>(this IEnumerable<T> value, Action<T> action)
{
  foreach (T item in value)
  {
    action(item);
  }
}

Bien que la méthode de All() fournit des capacités similaires, il est des cas d'utilisation est pour effectuer un test sous-jacente sur chaque élément et non une action. Bien sûr, il peut être amené à effectuer d'autres tâches, mais cela change quelque peu la sémantique et rendrait plus difficile pour les autres d'interpréter votre code (à savoir est cette utilisation de All() pour un test sous-jacente ou une action?).

Disclaimer: Ce poste ne ressemble plus à ma première réponse, mais intègre plutôt l'expérience des sept années, je l'ai acquise depuis. J'ai fait la modifier parce que c'est une question et aucune des réponses existantes très bien vu couvert tous les angles. Si vous voulez voir ma réponse initiale, il est disponible dans l'historique des révisions pour cette post.


La première chose à comprendre ici est des opérations C # LINQ comme Select(), All(), Where(), etc, ont leurs racines dans Il recommande d'utiliser une boucle de foreach traditionnelle:

  

[foreach ()] ajoute zéro nouveau pouvoir de représentation à la langue. Ce faisant, vous Réécrivons ce code parfaitement clair:

     

foreach(Foo foo in foos){ statement involving foo; }

     

dans ce code:

     

foos.ForEach(foo=>{ statement involving foo; });

Son point est, quand vous regardez attentivement vos options de syntaxe, vous ne gagnez pas quelque chose de nouveau à partir d'une extension ForEach() par rapport à une boucle de foreach traditionnelle. Je suis partiellement en désaccord. Imaginez que vous avez ceci:

 foreach(var item in Some.Long(and => possibly)
                         .Complicated(set => ofLINQ)
                         .Expression(to => evaluate)
 {
     // now do something
 } 

Ce code obscurcit sens, car il sépare le mot-clé foreach des opérations dans la boucle. Il indique également la commande de boucle avant pour les opérations qui définissent la séquence à laquelle la boucle fonctionne. Il se sent beaucoup plus naturel de vouloir avoir ces opérations viennent en premier, puis les faire la commande en boucle à la end de la définition de la requête. En outre, le code est juste laid. Il semble que ce serait beaucoup plus agréable d'être en mesure d'écrire ceci:

Some.Long(and => possibly)
   .Complicated(set => ofLINQ)
   .Expression(to => evaluate)
   .ForEach(item => 
{
    // now do something
});

Cependant, même ici, je suis venu finalement autour au point de vue d'Eric. J'ai réalisé code comme vous voyez ci-dessus est d'appeler pour une variable supplémentaire. Si vous avez un ensemble complexe d'expressions LINQ comme ça, vous pouvez ajouter des informations précieuses à votre code en attribuant d'abord le résultat de l'expression LINQ à une nouvelle variable:

var queryForSomeThing = Some.Long(and => possibly)
                        .Complicated(set => ofLINQ)
                        .Expressions(to => evaluate);
foreach(var item in queryForSomeThing)
{
    // now do something
}

Ce code semble plus naturel. Il met le mot-clé foreach retour à côté du reste de la boucle, et après la définition de la requête. La plupart de tous, le nom de la variable peut ajouter de nouvelles informations qui seront utiles aux futurs programmeurs qui essaient de comprendre le but de la requête LINQ. Encore une fois, nous voyons l'opérateur ForEach() souhaité vraiment ajouté aucune nouvelle expressivité du langage.

Cependant, nous manque encore deux caractéristiques d'une méthode hypothétique extension ForEach():

  1. Ce n'est pas composable. Je ne peux pas ajouter un .Where() plus ou GroupBy() ou OrderBy() après une ligne de boucle de foreach avec le reste du code, sans créer une nouvelle déclaration.
  2. Il est pas paresseux. Ces opérations se produisent immédiatement. Il n'a pas déjàbas moi, par exemple, un formulaire où l'utilisateur choisit une opération comme un champ dans un écran plus grand qui n'a pas été donné jusqu'à ce que l'utilisateur appuie sur un bouton de commande. Cette forme pourrait permettre à l'utilisateur de changer d'avis avant d'exécuter la commande. Ceci est parfaitement normal ( facile même) avec une requête LINQ, mais pas aussi simple avec un foreach.

Vous pouvez, bien sûr, faire votre propre méthode d'extension de ForEach(). Plusieurs autres réponses ont mises en œuvre de cette méthode déjà; ce n'est pas si compliqué que ça. Cependant, je me sens comme il est inutile. Il y a déjà une méthode existante qui correspond à ce que nous voulons faire des deux points de vue sémantique et opérationnel. Les deux caractéristiques manquantes ci-dessus peuvent être résolus par l'utilisation de l'opérateur Select() existant.

Select() correspond à la nature de la transformation ou de la projection décrite par les deux exemples ci-dessus. Gardez à l'esprit, cependant, que je voudrais éviter encore créer des effets secondaires. L'appel à Select() doit retourner soit de nouveaux objets ou des projections à partir des originaux. Cela peut parfois être aidé par l'utilisation d'un type anonyme ou objet dynamique (si et seulement si nécessaire). Si vous avez besoin des résultats à persister dans, disons, une variable de liste originale, vous pouvez toujours appeler .ToList() et l'assigner à votre variable d'origine. Je vais ajouter ici que je préfère travailler avec des variables IEnumerable<T> autant que possible sur les types plus concrets.

myList = myList.Select(item => new SomeType(item.value1, item.value2 *4)).ToList();

En résumé:

  1. Il suffit de coller avec foreach la plupart du temps.
  2. Lorsque foreach vraiment ne le fera pas (ce qui est probablement pas aussi souvent que vous le pensez), l'utilisation Select()
  3. Lorsque vous devez utiliser Select(), vous pouvez éviter encore généralement des effets secondaires (programme visibles), éventuellement en projetant à un type anonyme.

Malheureusement, il n'y a pas moyen intégré pour le faire dans la version actuelle de LINQ. L'équipe-cadre négligé d'ajouter une méthode d'extension .foreach. Il y a une bonne discussion à ce sujet passe en ce moment sur le blog suivant.

http://blogs.msdn.com/kirillosenkov/ archives / 2009/01/31 / foreach.aspx

Il est assez facile d'ajouter un bien.

public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) {
  foreach ( var cur in enumerable ) {
    action(cur);
  }
}

Vous ne pouvez pas le faire tout de suite avec LINQ et IEnumerable - vous devez soit implémenter votre propre méthode d'extension, ou jeter votre énumération à un tableau avec LINQ, puis appelez Array.ForEach ():

Array.ForEach(MyCollection.ToArray(), x => x.YourMethod());

S'il vous plaît noter qu'en raison des types de valeur de chemin et struct travail, si la collection est d'un type de valeur et que vous modifiez les éléments de la collection de cette façon, il n'a aucun effet sur les éléments de la collection originale.

Parce que LINQ est conçu pour être une fonction de requête et non une fonction de mise à jour, vous ne trouverez pas une extension qui exécute des méthodes sur IEnumerable parce que cela vous permettra d'exécuter une méthode (potentiellement des effets secondaires). Dans ce cas, vous pouvez tout aussi bien coller avec

  

foreach (nom de chaîne dans les noms)
  Console.WriteLine (nom);

Eh bien, vous pouvez également utiliser le mot-clé standard foreach, format Élargi dans un oneliner:

foreach(var n in Names.Where(blahblah)) DoStuff(n);

Désolé, cette option a pensé mérite d'être ici:)

Il existe une méthode ForEach hors de la liste. Vous pouvez convertir le Enumerable à la liste en appelant la méthode .ToList (), puis appeler la méthode ForEach hors de cela.

Sinon, je l'ai entendu parler de gens qui définissent leur propre méthode ForEach hors de IEnumerable. Ceci peut être accompli en appelant essentiellement la méthode ForEach, mais au lieu d'emballage dans une méthode d'extension:

public static class IEnumerableExtensions
{
    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> _this, Action<T> del)
    {
        List<T> list = _this.ToList();
        list.ForEach(del);
        return list;
    }
}

Utilisation parallèle Linq:

Names.AsParallel (). PourTout (name => ...)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top