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

时间:2015-06-01 11:37:53

标签: c# iterator

我有这个迭代器并希望它在某些条件下停止,因此,有一个名为“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
}

不幸的是,这个参数在内部循环中没有改变,所以现在总是如此,因为它似乎只在第一次迭代时执行。

问题:如何在每次迭代中检查或执行“条件”?

2 个答案:

答案 0 :(得分:8)

参数是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表达式,类似于布尔函数,不含参数,返回i++ < 100

答案 1 :(得分:2)

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

相反,你需要传递一个代表,你&#34;委托&#34;向调用者提供规则的责任。

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

public delegate T Func<T>();

这是一个委托,它包装一个返回值的方法,而不需要任何参数。

由于您希望在while语句中使用此函数的结果,因此需要它返回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;
}

但是用较小的语法包装。

现在,每次循环运行一次迭代时,它将调用此func,这将增加该值并将其与100进行比较。