Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle an "infinite" IEnumerable?

A trivial example of an "infinite" IEnumerable would be

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

I know, that

foreach(int i in Numbers().Take(10)) {   Console.WriteLine(i); } 

and

var q = Numbers(); foreach(int i in q.Take(10)) {   Console.WriteLine(i); } 

both work fine (and print out the number 0-9).

But are there any pitfalls when copying or handling expressions like q? Can I rely on the fact, that they are always evaluated "lazy"? Is there any danger to produce an infinite loop?

like image 624
Danvil Avatar asked Apr 29 '10 19:04

Danvil


2 Answers

As long as you only call lazy, un-buffered methods you should be fine. So Skip, Take, Select, etc are fine. However, Min, Count, OrderBy etc would go crazy.

It can work, but you need to be cautious. Or inject a Take(somethingFinite) as a safety measure (or some other custom extension method that throws an exception after too much data).

For example:

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;     } } 
like image 86
Marc Gravell Avatar answered Sep 24 '22 04:09

Marc Gravell


Yes, you are guaranteed that the code above will be executed lazily. While it looks (in your code) like you'd loop forever, your code actually produces something like this:

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; }     } } 

(This obviously isn't exactly what will be generated, since this is pretty specific to your code, but it's nonetheless similar and should show you why it's going to be lazily evaluated).

like image 25
Adam Robinson Avatar answered Sep 22 '22 04:09

Adam Robinson