2009-03-20 10 views
6

Supposons que j'ai un code qui ressemble à ceci:C# Code de simplification Question: Séquentielle Foreach boucles

foreach(type x in list y) 
{ 
    //dostuff1(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff2(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff3(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff4(x) 
} 

foreach(type x in list y) 
{ 
    //dostuff5(x) 
} 

Je ne peux combiner les choses dans une grande boucle comme ceci:

foreach (type x in list y) 
{ 
    //dostuff1(x) 
    //dostuff2(x) 
    //dostuff3(x) 
    //dostuff4(x) 
    //dostuff5(x) 
} 

Ce faisant, changerait l'ordre. Des commentaires sur les meilleurs moyens de rendre le code plus simple en C#?

j'imagine que je pouvais résoudre ce problème en créant une fonction de ce genre, mais je préfère le laisser comme ça que la force futurs lecteurs de mon code pour comprendre yield:

void func(type x) 
{ 
    dostuff1(x) 
    yield 0; 
    dostuff2(x) 
    yield 0; 
    dostuff3(x) 
    yield 0; 
    dostuff4(x) 
    yield 0; 
    dostuff5(x) 
    yield break; 
} 

for (int i = 0; i<5; ++i) 
{ 
    foreach (type x in list y) 
    { 
     //Call func(x) using yield semantics, which I'm not going to look up right now 
    } 
} 

Répondre

30

Une autre alternative:

List<Action<Foo>> actions = new List<Action<Foo>> { 
    doStuff1, doStuff2, doStuff3, doStuff4, doStuff5 
}; 

foreach (Action<Foo> action in actions) 
{ 
    foreach (Foo x in list) 
    { 
     action(x); 
    } 
} 

Vérifié, et cela fonctionne. Par exemple:

using System; 
using System.Collections.Generic; 

public class Test 
{ 
    static void Main(string[] args) 
    { 
     var actions = new List<Action<string>> { 
      First, Second 
     }; 

     foreach (var action in actions) 
     { 
      foreach (string arg in args) 
      { 
       action(arg); 
      } 
     } 
    } 

    static void First(string x) 
    { 
     Console.WriteLine("First: " + x); 
    } 

    static void Second(string x) 
    { 
     Console.WriteLine("Second: " + x); 
    } 
} 

Résultats de l'exécution Test.exe a b c

First: a 
First: b 
First: c 
Second: a 
Second: b 
Second: c 
+0

+1 - Les délégués sont bien mieux en C# que dans VB.NET :( –

2

Que diriez-vous:

interface IDoStuff 
{ 
    void DoStuff(x); 
} 

List<IDoStuff> listOfActions = ... 
foreach (IDoStuff iDoStuff in listOfActions) 
{ 
    foreach (type x in list y) 
    { 
     iDoStuff(x); 
    } 
} 

[modifier] Et oui, vous devriez plutôt opter pour la solution générique J. Skeet a dit (bien que vous puissiez utiliser une interface générique au lieu d'un délégué aussi).

+0

Pourquoi utiliser une interface lorsque les délégués sont tellement plus pratique? :) –

+0

Vous avez raison ..Mais je les préfère parfois quand j'ai besoin d'associer un état à l'action, juste pour encapsuler chaque action + données dans une classe séparée (pas que vous ne pouvez pas passer un autre délégué public d'une classe différente). Ou pensez-vous que les délégués devrait être utilisé dans ces cas aussi bien? – Groo

+0

Voici quelques avantages pour les délégués: 1) Vous pouvez utiliser des expressions lambda et des méthodes anonymes (qui fournissent un support de fermeture - état associatif!) 2) Vous pouvez avoir plusieurs instances de délégué de la même classe - beaucoup moins encombrant que d'avoir une classe par implémentation d'interface. –

0

Si vous devez conserver la nature séquentielle, vous ne pouvez pas faire grand-chose. Vous pouvez faire quelques raccourcis de méthode d'extension, mais à mon humble avis cela rend le code moins lisible. En outre, vous pouvez rencontrer des problèmes en fonction des signatures de votre méthode.

Vous pouvez refactoriser pour déplacer l'itération vers des fonctions distinctes.

// Method 1 
DoStuff1ToList(y); 
DoStuff2ToList(y); 
DoStuff3ToList(y); 
DoStuff4ToList(y); 
DoStuff5ToList(y); 

// Do Stuff 1 
foreach (var x in y) 
{ 
    // do actual stuff 
} 
5

Si vous avez une liste assez constante d'actions, vous pouvez simplement éviter les boucles foreach, mais toujours faire les actions explicitement (ont pas testé le code):

list.ForEach(action1); 
list.ForEach(action2); 
list.ForEach(action3); 
list.ForEach(action4); 
0

Je pense que ce est le même que testing.ForEach (action) alors utilisez-le si vous descendez ce type de route.

private static void DoDifferentStuffToThings() 
    { 
     List<string> testing = new List<string>() { "hello", "world" }; 

     Action<string> action1 = (a) => 
     { 
      Console.WriteLine("Action 1 {0}", a); 
     }; 

     Action<string> action2 = (a) => 
     { 
      Console.WriteLine("Action 2 {0}", a); 
     }; 

     DoStuffToThings<string>(testing, action1); 
     DoStuffToThings<string>(testing, action2); 
    } 

    private static void DoStuffToThings<T>(IEnumerable<T> list, Action<T> dothing) 
     where T : class 
    { 
     foreach (var item in list) 
     { 
      dothing(item); 
     } 
    } 
5

La réponse de Jon Skeet est excellente (je viens de voter en haut). Voici une idée pour aller plus loin:

Si vous faites cela souvent, vous pouvez créer une méthode d'extension appelée "DoActionsInOrder" (ou peut-être vous pouvez trouver un meilleur nom) qui fait cela. Voici l'idée:

public static void DoActionsInOrder<T>(this IEnumerable<T> stream, params Action<T> actionList) 
{ 
    foreach(var action in actionList) 
    { 
      foreach(var item in stream) 
      { 
       action(item); 
      } 
    } 
} 

Ensuite, vous pouvez l'appeler comme ceci:

myList.DoActionsInOrder(doStuff1, doStuff2, doStuff3, doStuff4, doStuff5); 
+0

damn synchronicité! Je viens de terminer la même méthode d'extension. La seule différence que je peux voir est que vous utilisez var au lieu de T :) +1, alors! – flq

+0

:) Merci. C'est incroyable de voir comment ce site nous demande de répondre aux questions des autres aussi vite que possible! Je pourrais devenir accro! –