自定义迭代器的实现不会更改其参数之一

Implementation of custom iterator does not change one of its parameters

我有这个迭代器并希望它在某些情况下停止,因此,有一个名为 "condition" 的第三个参数。

public static IEnumerable<long> Dates(long start, int step, bool condition)
{
    var k = start + step;

    while (condition)
    {
        k += step;
        yield return k;
    }
}

我这样称呼它:

var i = 0;

foreach (var k in Iterator.Dates(0, 5, i++ < 100))
{
    // Here goes infinite loop because (i++ < 100) is always true inside iterator
}

不幸的是,此参数不会在循环内更改,所以现在它始终为真,因为它似乎只在第一次迭代时执行。

问题:如何在每次迭代时检查或执行"condition"?

参数是 bool,但你需要像这样的谓词函数:

public static IEnumerable<long> Dates(long start, int step, Func<bool> condition)
{
    var k = start + step;

    while (condition())
    {
        k += step;
        yield return k;
    }
}

用法:

var i = 0;

foreach (var k in Dates(0, 5, () => i++ < 100))
{
    // Here goes infinite loop because (i++ < 100) is always true inside iterator
}

评论

() => i++ < 100 是类似于布尔函数的 lambda 表达式 没有参数 即 returns i++ < 100.

您想要提供的是一项功能,一个规则。相反,你提供了一个 value,这个值是在调用方法之前在表达式中计算的,因此在方法内部它是常量,永远不会改变,就像你观察到的那样。

相反,您需要传递一个委托,您 "delegate" 有责任向调用者提供规则。

适合此示例的简单委托类型是 Func<T>,其基本定义如下:

public delegate T Func<T>();

这是一个委托,它包装了一个 return 是一个值的方法,不带任何参数。

由于要在 while 语句中使用此函数的结果,因此需要它 return bool.

声明方法的方式如下:

public static IEnumerable<long> Dates(long start, int step, Func<bool> condition)
{
    var k = start + step;

    while (condition())
    {
        k += step;
        yield return k;
    }
}

请注意,您需要将 while 表达式更改为 调用 委托。因为它包装了一个方法,所以要从你必须调用它的方法中获取值。

调用新方法的方法如下:

var i = 0;

foreach (var k in Iterator.Dates(0, 5, () => i++ < 100))
{
    // No longer infinite loop because (i++ < 100) is now evaluated on every iteration
}

这个新表达式:

() => i++ < 100

和这样写基本一样:

int i;
bool Func()
{
    return i++ < 100;
}

但包含在更小的语法中。

现在,循环每运行一次迭代,它就会调用这个函数,它会增加值并将其与 100 进行比较。