C# 如何处理一个“问题”;“无限”;我可数?

C# 如何处理一个“问题”;“无限”;我可数?,c#,enumeration,infinite-loop,yield-return,C#,Enumeration,Infinite Loop,Yield Return,“无限”IEnumerable的一个小例子是 IEnumerable<int> Numbers() { int i=0; while(true) { yield return unchecked(i++); } } 及 两者都可以正常工作(并打印出数字0-9) 但是,在复制或处理诸如q之类的表达式时,是否存在任何陷阱?我能相信他们总是被评价为“懒惰”这一事实吗?是否存在产生无限循环的危险?是的,可以保证上面的代码将被延迟执行。虽然(在您的代码中)看起来您将永远循

“无限”IEnumerable的一个小例子是

IEnumerable<int> Numbers() {
  int i=0;
  while(true) {
    yield return unchecked(i++);
  }
}

两者都可以正常工作(并打印出数字0-9)


但是,在复制或处理诸如
q
之类的表达式时,是否存在任何陷阱?我能相信他们总是被评价为“懒惰”这一事实吗?是否存在产生无限循环的危险?

是的,可以保证上面的代码将被延迟执行。虽然(在您的代码中)看起来您将永远循环,但您的代码实际上会产生如下结果:

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; }
    }
}
IEnumerable number()
{
返回新的PrivateNumberEnumerable();
}
私有类PrivateNumberEnumerable:IEnumerable
{
公共IEnumerator GetEnumerator()
{ 
返回新的PrivateNumbersEnumerator();
}
}
私有类PrivateNumber分子:IEnumerator
{
私人互联网i;
public bool MoveNext(){i++;返回true;}
公共电流
{
获取{return i;}
}
}

(这显然不是将要生成的内容,因为这对于您的代码来说是非常特定的,但它仍然是类似的,并且应该向您说明为什么要对其进行惰性计算)。

只要您只调用惰性的、未缓冲的方法,您就可以了。因此,
跳过
接受
选择
,等等都可以。然而,
Min
Count
OrderBy
等都会变得疯狂

它可以工作,但你需要谨慎。或者注入一个
Take(somethingfimited)
作为安全措施(或者在数据过多后抛出异常的其他自定义扩展方法)

例如:

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;
    }
}
公共静态IEnumerable SanityCheck(此IEnumerable数据,int max){
int i=0;
foreach(数据中的T项){
如果(++i>=max)抛出新的InvalidOperationException();
收益回报项目;
}
}

您必须避免任何贪婪函数试图读取到末尾。这将包括可枚举的扩展,如:
Count
ToArray
/
ToList
,以及聚合
Avg
/
Min
/
Max
,等等

无限懒惰列表并没有错,但您必须有意识地决定如何处理它们


使用
Take
通过设置上限来限制无止境循环的影响,即使您不需要所有上限。

是的,您的代码将始终在无止境循环的情况下工作。也许有人会晚一点来把事情搞砸。假设他们想做:

var q = Numbers().ToList();

然后,你就被冲了!许多“聚合”函数会杀死你,比如
Max()

如果不是惰性计算,你的第一个例子就不会像预期的那样工作。

只是挑剔一点,当i=Int32.MaxValue而你做i++时,你的“无限”例子不会抛出异常吗?还是循环到Int32.MinValue?嗯……你说得对。它可能会引发溢出异常。。。我会编辑它。只是在这里挑三拣四,你的观点仍然被人理解。:)另外,我尝试了它,它确实循环到Int32.MinValue。没有OverflowException,因此它实际上是一个无限循环。默认情况下,C#编译时不进行溢出检查。安全的方法总是不检查地编写(i++),因为您可以使用/checked进行编译,然后它会呕吐。使用unchecked()告诉编译器,即使使用/checked.Than编译也可以发生溢出。返回到更漂亮的原始版本:D+1我有一个相互竞争的答案,但我只需要对IEnumerable的扩展方法SanityCheck投上一票。有史以来最好的函数名。我要去实现它+我感谢你指出这一点。另外,如果OP实际调用了foreach(inti in Numbers()),也会导致问题。
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;
    }
}
var q = Numbers().ToList();