代码之家  ›  专栏  ›  技术社区  ›  Brian

C代码简化查询:顺序foreach循环

c#
  •  6
  • Brian  · 技术社区  · 15 年前

    假设我有一些这样的代码:

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

    我不能像这样把事情组合成一个大的for循环:

    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
       }
    }
    
    6 回复  |  直到 15 年前
        1
  •  30
  •   Jon Skeet    15 年前

    另一种选择:

    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
    
        2
  •  5
  •   Grzenio    15 年前

    如果您有一个相当稳定的操作列表,您可以避免foreach循环,但仍然显式地执行这些操作(尚未测试代码):

    list.ForEach(action1);
    list.ForEach(action2);
    list.ForEach(action3);
    list.ForEach(action4);
    
        3
  •  5
  •   Charlie Flowers    15 年前

    乔恩·斯基特的回答很好(我刚刚投了赞成票)。下面是一个更进一步的想法:

    如果您经常这样做,您可以创建一个名为“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);
    
        4
  •  2
  •   vgru    15 年前

    怎么样:

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

    [编辑] 是的,您应该像J.Skeet所说的那样使用通用解决方案(尽管您也可以使用通用接口而不是委托)。

        5
  •  0
  •   Matt Brunell    15 年前

    如果你必须保持连续性,那你就没什么能做的了。您可以做一些扩展方法快捷方式,但是imho这使得代码可读性变差。此外,根据方法签名,您可能会遇到问题。

    您可以重构以将迭代移动到单独的函数。

    // Method 1
    DoStuff1ToList(y);
    DoStuff2ToList(y);
    DoStuff3ToList(y);
    DoStuff4ToList(y);
    DoStuff5ToList(y);
    
    // Do Stuff 1
    foreach (var x in y)
    { 
        // do actual stuff
    }
    
        6
  •  0
  •   Hath    15 年前

    我想这和测试是一样的。 所以如果你走这种路线,就用这个。

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