Wilsonhut

Deal with it or don't

Obvious Extension Methods: IEnumerable Cache

So you don’t want to do a ToList(), but you don’t want to enumerate your IEnumerable<T> more than once? How about an extension method called “Cache” that Caches the output as you go.

  1. public static class Extensions
  2. {
  3.     public static CachedEnumerable<T> Cache<T>(this IEnumerable<T> enumerable)
  4.     {
  5.         return new CachedEnumerable<T>(enumerable);
  6.     }
  7. }
  8. public class CachedEnumerable<T> : IEnumerable<T>
  9. {
  10.     IEnumerator<T> _originalEnumerator;
  11.     readonly IEnumerable<T> _originalEnumerable;
  12.     readonly List<T> _cache = new List<T>();
  13.     public CachedEnumerable(IEnumerable<T> enumerable)
  14.     {
  15.         _originalEnumerable = enumerable;
  16.     }
  17.     public IEnumerator<T> GetEnumerator()
  18.     {
  19.         foreach (var t in _cache)
  20.         {
  21.             yield return t;
  22.         }
  23.         if (_originalEnumerator == null)
  24.         {
  25.             _originalEnumerator = _originalEnumerable.GetEnumerator();
  26.         }
  27.         while (_originalEnumerator.MoveNext())
  28.         {
  29.             _cache.Add(_originalEnumerator.Current);
  30.             yield return _originalEnumerator.Current;
  31.         }
  32.     }
  33.     IEnumerator IEnumerable.GetEnumerator()
  34.     {
  35.         return GetEnumerator();
  36.     }
  37. }

That’s it. If you want to see it in action, open LINQPad, select Language: “C# Program”, delete everything, paste in the above, then finally, paste in the below:

void Main()
{
  var x = GetNumbers().Cache();

  "TAKE 2.".Dump();
  x.Take(2).Dump("TWO:");

  "Get them all.".Dump();
  x.Dump("ALL:");

  "Get them all again.".Dump();
  x.Dump("ALL:");
}

public IEnumerable<T> GetNumbers()
{
  yield return 1.Dump("Numbers is hard");
  Thread.Sleep(500);
  yield return 2.Dump("Numbers is hard");
  Thread.Sleep(500);
  yield return 3.Dump("Numbers is hard");
  Thread.Sleep(500);
  yield return 4.Dump("Numbers is hard");
  Thread.Sleep(500);
  yield return 5.Dump("Numbers is hard");
  Thread.Sleep(500);
  yield return 6.Dump("Numbers is hard");
}

There.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: