I've an IEnumerable<T>
source which takes time to generate each item. Once an item is generated, I want to cache it to avoid recomputing the same thing. I want to separate out caching logic from original source.
A few things that bother me are:
- Where should I have
_cache
? InCachedEnumerable
orCacheEnumerator
? - Thread safety in adding into cache.
- Reinventing? Any existing .NET or other library which does this.
- Why
Dispose
inIEnumerator
? Should I be doing something there?_cache
nuke?
class CachedEnumerable<T> : IEnumerable<T>
{
private IList<T> _cache = new List<T>();
IEnumerator<T> _cacheEnumerator = null;
IEnumerable<T> _source = null;
public CachedEnumerable(IEnumerable<T> source)
{
_source = source;
_cacheEnumerator = _source.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return new CachedEnumerator<T>(_cache, _cacheEnumerator);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class CachedEnumerator<T> : IEnumerator<T>
{
private IList<T> _cache;
private IEnumerator<T> _source;
private T _current;
private int _index;
private bool _moveNextStatus;
public CachedEnumerator(IList<T> cache, IEnumerator<T> source)
{
_cache = cache;
_source = source;
Reset();
}
public T Current
{
get
{
if (_moveNextStatus)
{
return _current;
}
else
{
throw new InvalidOperationException();
}
}
}
public void Dispose()
{
_source.Dispose();
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
_moveNextStatus = _MoveNext();
return _moveNextStatus;
}
private bool _MoveNext()
{
_index++;
if (_index < _cache.Count)
{
_current = _cache[_index];
return true;
}
else
{
if (_source.MoveNext())
{
_current = _source.Current;
_cache.Add(_current);
return true;
}
else
{
return false;
}
}
}
public void Reset()
{
_index = -1;
_current = default(T);
_moveNextStatus = false;
}
}