自定义迭代器的实现不改变其参数之一
本文关键字:参数 改变 迭代器 实现 自定义 | 更新日期: 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进行比较。