2009-03-20 3 views
6

Пусть у меня есть некоторый код, который выглядит следующим образом:C# код Упрощение запроса: Последовательная Foreach Loops

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

Я не могу сочетать вещи в один большой цикл как это:

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

Это изменит порядок. Любой комментарий о лучших способах сделать код проще на C#?

Я полагаю, я мог бы решить эту проблему, создав такую ​​функцию, хотя я предпочел бы оставить его таким, каким он является, чем заставить будущих читателей моего кода, чтобы понять 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 
    } 
} 

ответ

30

Другой альтернативный:

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

Только что проверено, и это работает. Например:

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

Результаты работы Test.exe a b c

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

+1 - Делегаты в C# намного лучше, чем в VB.NET :( –

2

Как насчет:

interface IDoStuff 
{ 
    void DoStuff(x); 
} 

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

[править] И да, вам лучше пойти на общее решение, как J. Скит сказал (хотя вы можете использовать общий интерфейс, а не делегат).

+0

Зачем использовать интерфейс, когда делегаты гораздо удобнее? :) –

+0

Вы правы ..Но иногда я предпочитаю их, когда мне нужно связать какое-то состояние с действием, просто чтобы инкапсулировать каждое действие + данные в отдельный класс (не то, что вы не можете передать другой публичный делегат из другого класса). Или вы считаете, что делегаты следует также использовать в этих случаях? – Groo

+0

Здесь есть несколько преимуществ для делегатов: 1) Вы можете использовать лямбда-выражения и анонимные методы (которые предоставляют поддержку закрытия - связывая состояние!) 2) У вас может быть несколько экземпляров делегата из того же класса - гораздо меньше беспорядка, чем один класс для реализации интерфейса. –

0

Если вы должны сохранить последовательный характер, вы не можете многое сделать. Вы можете использовать некоторые быстрые клавиши расширения, но IMHO делает это для менее читаемого кода. Кроме того, вы можете столкнуться с проблемами в зависимости от ваших сигнатур методов.

Вы можете реорганизовать, чтобы переместить итерацию в отдельные функции.

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

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

Если у вас есть достаточно постоянный список действий, вы могли бы просто избежать цикл просмотра, но до сих пор действия явно (не тестировал код):

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

я думаю, что это это то же самое, что и test.ForEach (действие) , поэтому просто используйте это, если вы идете по этому маршруту.

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

Ответ Джона Скита превосходный (я только что проголосовал). Вот идея сделать это еще на один шаг:

Если вы делаете это много, вы можете сделать метод расширения, называемый «DoActionsInOrder» (или, может быть, вы можете придумать лучшее имя), который сделает это. Вот идея:

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

Тогда вы могли бы назвать это так:

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

проклятая синхронизация! Я только что закончил тот же метод расширения. Единственное различие, которое я вижу, это то, что вы используете var вместо T :) +1, тогда! – flq

+0

:) Спасибо. Удивительно, как этот сайт требует, чтобы мы как можно быстрее ответили на вопросы других людей! Я мог бы стать зависимым! –

Смежные вопросы