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

本文关键字:参数 改变 迭代器 实现 自定义 | 更新日期: 2023-09-27 17:51:18

我有这个迭代器,并希望它在某些条件下停止,因此,有第三个参数称为"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表达式,类似于不带参数的布尔函数,返回i++ < 100

您想要提供的是一个功能,一个规则。相反,您提供了一个,该值在调用方法之前在表达式中计算,因此在方法内部它是常量,永远不会改变,正如您所看到的。

你需要传递一个委托,你把提供规则的责任"委托"给调用者。

适合这个例子的一个简单的委托类型是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;
}

但是用更小的语法包装。

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