【问题标题】:Infinite IEnumerable in a foreach loopforeach 循环中的无限 IEnumerable
【发布时间】:2009-05-05 19:44:20
【问题描述】:

在回答this question之后,我整理了以下C#代码,只是为了好玩:

public static IEnumerable<int> FibonacciTo(int max)
{     
    int m1 = 0;
    int m2 = 1;
    int r = 1;

    while (r <= max)
    {
       yield return r;

       r = m1 + m2;
       m1 = m2;
       m2 = r;
    }
}

foreach (int i in FibonacciTo(56).Where(n => n >= 24) )
{
   Console.WriteLine(i);
}

问题是我不喜欢将max 参数传递给函数。现在,如果我不使用其中一个,代码将输出正确的数据,但随着 IEnumerable 继续工作,它似乎会挂起。我怎样才能写这个,以便我可以像这样使用它:

foreach (int i in Fibonacci().Where(n => n >= 24 && n <= 56) )
{
   Console.WriteLine(i);
}

【问题讨论】:

    标签: c# linq yield


    【解决方案1】:

    您需要改用SkipWhileTakeWhile 的组合。

    foreach (int i in Fibonacci().SkipWhile(n => n < 24)
                                 .TakeWhile(n => n <= 56))
    {
       Console.WriteLine(i);
    }
    

    这些能够根据条件结束循环; Where 流式传输其输入(适当过滤),直到输入用完(在您的情况下,永远不会)。

    【讨论】:

    • 我刚刚想通了,正准备自己发布。奇怪的是,最终写出问题有时会指向明显的问题
    • 嗯...我的基本问题是我只专注于在一个 lambda 表达式中执行此操作。现在我也很想写一个新的“SkipThenTakeWhile()”IEnumerable 扩展,只要我能想出一个更好的名字就可以了;)
    • 虽然我也喜欢编写 LINQ 运算符,但我怀疑这是否真的经常出现,值得一提;)
    【解决方案2】:

    除非您编写自己的 LINQ 提供程序,否则我认为这是不可能的。在您提供的示例中,您使用的是 LINQ to Objects,它需要完全评估 IEnumerable,然后才能对其应用过滤器。

    【讨论】:

    • 谢天谢地 IEnumerable 并不是这样工作的:它在评估时应用过滤器,因此数据是流式传输而不是重复的。
    • 乔尔,你是对的,我忘记了函数式编程的基本原则,其中操作不会产生副作用。
    猜你喜欢
    • 2017-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多