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

帮助我理解C语言中的代码片段#

  •  10
  • Benny  · 技术社区  · 14 年前

    我在读这个博客: Pipes and filters pattern

    我被这段代码搞糊涂了:

    public class Pipeline<T>
    {
        private readonly List<IOperation<T>> operations = new List<IOperation<T>>();
    
        public Pipeline<T> Register(IOperation<T> operation)
        {
            operations.Add(operation);
            return this;
        }
    
        public void Execute()
        {
            IEnumerable<T> current = new List<T>();
            foreach (IOperation<T> operation in operations)
            {
                current = operation.Execute(current);
            }
            IEnumerator<T> enumerator = current.GetEnumerator();
            while (enumerator.MoveNext());
        }
    }
    

    本声明的目的是: while(枚举器.moveNext()); ?看来这密码是个陷阱。

    3 回复  |  直到 14 年前
        1
  •  7
  •   Mark Byers    14 年前

    首先考虑一下:

    IEnumerable<T> current = new List<T>();
    foreach (IOperation<T> operation in operations)
    {
        current = operation.Execute(current);
    }
    

    这段代码似乎正在创建嵌套的可枚举性,每一个可枚举性都接受前一个元素,对它们应用一些操作,并将结果传递给下一个。但它只构造可枚举的。实际上什么也没发生。它已经准备好了,存储在变量中 current . 有很多方法可以实现 IOperation.Execute 但可能是这样的。

    IEnumerable<T> Execute(IEnumerable<T> ts)
    {
        foreach (T t in ts)
            yield return this.operation(t); // Perform some operation on t.
    }
    

    本文建议的另一种选择是:

    IEnumerable<T> Execute(IEnumerable<T> ts)
    {
        // Thank-you LINQ!
        // This was 10 lines of non-LINQ code in the original article.
        return ts.OrderBy(t => t.Foo);
    }
    

    现在看看这个:

    IEnumerator<T> enumerator = current.GetEnumerator();
    while (enumerator.MoveNext());
    

    这实际上导致了操作链的执行。当从枚举请求元素时,它会导致原始可枚举的元素通过 IOperations ,每个都对它们执行一些操作。最终结果将被丢弃,因此只有操作的副作用是有趣的,例如写入控制台或记录到文件。这是写最后两行的更简单的方法:

    foreach (T t in current) {}
    

    另一件要注意的事情是,启动进程的初始列表是一个空列表,因此为了让它有意义,必须在第一个操作中创建一些t实例。在本文中,这是通过请求用户从控制台输入来完成的。

        2
  •  3
  •   Damian Powell    14 年前

    在这种情况下, while (enumerator.MoveNext()); 只是简单地评估最终结果返回的所有项目 IOperation<T> . 看起来有点混乱,但是空的 List<T> 只为向第一个 操作<t> .

    在许多集合中,这不会像您建议的那样起到任何作用,但是考虑到我们正在讨论管道和过滤器模式,最终的值很可能是某种迭代器,它将导致代码被执行。它可能是这样的,例如(假设这是一个整数):

    public class WriteToConsoleOperation : IOperation<int>
    {
        public IEnumerable<int> Execute(IEnumerable<int> ints)
        {
            foreach (var i in ints)
            {
                Console.WriteLine(i);
                yield return i;
            }
         }
    }
    

    如此呼唤 MoveNext() 对于上的每个项目 IEnumerator<int> 此迭代器返回的值将返回每个值(在 while 循环),但也将每个值输出到控制台。

    这有道理吗?

        3
  •  1
  •   kemiller2002    14 年前
    while (enumerator.MoveNext());
    

    在当前代码块中,没有任何影响(它会遍历枚举中的所有项)。显示的代码不作用于枚举中的当前元素。可能发生的情况是moveNext()方法正在移动到下一个元素,它正在对集合中的对象执行某些操作(更新内部值、从数据库中提取下一个值等)。因为类型是 List<T> 可能不是这样,但在其他情况下可能是这样。