Dan*_*vil 26 c# enumeration infinite-loop yield-return
"无限"IEnumerable的一个简单例子
IEnumerable<int> Numbers() {
int i=0;
while(true) {
yield return unchecked(i++);
}
}
Run Code Online (Sandbox Code Playgroud)
我知道
foreach(int i in Numbers().Take(10)) {
Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)
和
var q = Numbers();
foreach(int i in q.Take(10)) {
Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)
两者都工作正常(并打印数字0-9).
但复制或处理表达式时是否有任何陷阱q?我可以依赖这样一个事实,即它们总是被评估为"懒惰"吗?产生无限循环有危险吗?
Mar*_*ell 19
只要你只调用懒惰的,无缓冲的方法,你应该没问题.所以Skip,Take,Select,等都是精品.然而Min,Count,OrderBy等会发疯的.
它可以工作,但你需要谨慎.或者注入一个Take(somethingFinite)安全措施(或一些其他自定义扩展方法,在太多数据后抛出异常).
例如:
public static IEnumerable<T> SanityCheck<T>(this IEnumerable<T> data, int max) {
int i = 0;
foreach(T item in data) {
if(++i >= max) throw new InvalidOperationException();
yield return item;
}
}
Run Code Online (Sandbox Code Playgroud)
是的,您可以保证上面的代码会被懒散地执行.虽然它看起来(在你的代码中)就像你永远循环一样,但你的代码实际上产生了这样的东西:
IEnumerable<int> Numbers()
{
return new PrivateNumbersEnumerable();
}
private class PrivateNumbersEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new PrivateNumbersEnumerator();
}
}
private class PrivateNumbersEnumerator : IEnumerator<int>
{
private int i;
public bool MoveNext() { i++; return true; }
public int Current
{
get { return i; }
}
}
Run Code Online (Sandbox Code Playgroud)
(这显然是不准确究竟会产生,因为这是非常具体的,以你的代码,但它仍然相似,应该告诉你为什么它会被懒惰地评估).
你必须避免任何试图读取的贪婪函数.这将包括Enumerable像扩展:Count,ToArray/ ToList,和骨料Avg/ Min/ Max等
无限懒惰列表没有任何问题,但你必须有意识地决定如何处理它们.
用于Take通过设置上限来限制无限循环的影响,即使您不需要它们也是如此.
| 归档时间: |
|
| 查看次数: |
3935 次 |
| 最近记录: |