2009-03-20 9 views
6

Angenommen, ich habe einige Codes, der wie folgt aussieht:C# -Code Vereinfachung Abfrage: Die sequenzielle foreach-Schleife

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) 
} 

ich die Dinge nicht in einen großen for-Schleife wie folgt kombinieren:

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

Doing so würde die Reihenfolge ändern. Irgendwelche Kommentare zu den besten Möglichkeiten, den Code in C# einfacher zu machen?

Ich stelle mir vor ich dieses Problem durch die Schaffung einer Funktion wie diese lösen könnte, obwohl ich eher den Weg verlassen würde es als zukünftige Leser meines Code yield zu verstehen zwingen:

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 
    } 
} 

Antwort

30

Eine weitere 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); 
    } 
} 

Nur überprüft, und das funktioniert. Zum Beispiel:

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); 
    } 
} 

Ergebnisse Test.exe a b c

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

+1 - Die Delegierten sind so viel schöner in C# als in VB.NET :( –

2

läuft Wie wäre:

interface IDoStuff 
{ 
    void DoStuff(x); 
} 

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

[Bearbeiten] Und ja, man sollte eher für die generische Lösung als J. gehen Skeet sagte (obwohl Sie eine generische Schnittstelle anstelle eines Delegaten auch verwenden können).

+0

Warum eine Schnittstelle verwenden, wenn die Delegierten sind so viel bequemer? :) –

+0

Du hast Recht ..Aber ich bevorzuge sie manchmal, wenn ich einen Zustand mit der Aktion assoziieren muss, nur um jede Aktion + Daten in einer separaten Klasse zu kapseln (nicht dass du nicht auch einen anderen öffentlichen Delegaten aus einer anderen Klasse weitergeben könntest). Oder denkst du Delegaten? sollte in diesen Fällen auch verwendet werden? – Groo

+0

Es gibt ein paar Vorteile für die Delegierten hier: 1) Sie können Lambda-Ausdrücke und anonyme Methoden (die Schließung Unterstützung - assoziieren Zustand!) 2) Sie können mehrere Delegat Instanzen aus der gleichen Klasse haben - viel weniger Unordnung als haben eine Klasse pro Schnittstellenimplementierung. –

0

Wenn Sie die sequenzielle Natur beibehalten müssen, können Sie nicht viel tun. Sie könnten einige Shortcuts für Erweiterungsmethoden verwenden, aber IMHO macht dies weniger lesbaren Code. Je nach Methodensignatur können auch Probleme auftreten.

Sie könnten die Iteration umgestalten, um Funktionen zu trennen.

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

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

Wenn Sie eine ziemlich konstante Liste von Aktionen haben, können Sie nur die foreach-Schleifen vermeiden, aber immer noch die Aktionen tun explizit (nicht den Code getestet):

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

Ich denke, das ist das gleiche wie testing.ForEach (action) so verwenden Sie einfach, wenn Sie diese Art von Route hinunter.

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

Jon Skeets Antwort ist ausgezeichnet (ich habe es gerade gewählt). Hier ist eine Idee, um einen Schritt weiter zu gehen:

Wenn Sie dies viel tun, könnten Sie eine Erweiterungsmethode namens "DoActionsInOrder" (oder vielleicht können Sie mit einem besseren Namen kommen), die dies tut. Hier ist die Idee:

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); 
      } 
    } 
} 

Dann Sie es so nennen könnte:

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

verdammt synchronität! Ich habe gerade die exakt gleiche Erweiterungsmethode beendet. Der einzige Unterschied, den ich sehen kann ist, dass Sie var anstelle von T :) +1 verwenden, dann! – flq

+0

:) Danke. Es ist erstaunlich, wie diese Seite uns dazu bringt, so schnell wie möglich die Fragen anderer zu beantworten! Ich könnte süchtig werden! –

Verwandte Themen