Home > Computers and Internet > Indexed Cached Collections

Indexed Cached Collections

The IEnumberable<T> type in .Net is awesome. It allows for lazy initializing of data. This can be good, this can be bad. This is really good when you don’t enumerate over the entire collection. This is bad when you enumerate over the collection more than once. Andrew Arnott wrote up a caching enumerator, which is great for most cases; Caching results of .NET IEnumerable<T> generator methods. I’m currently in a situation where I want to cache the results, but the code doesn’t need to enumerate over the collection, it needs to index into the collection. So I wrote up these two classes to solve the problem.

namespace CachedCollection
{
    /// <summary>
    /// Access data in an indexed collection where the source of the data is lazy evaluated
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class IndexableCachedEnumeration<T>
    {
        private List<T> listCache;
        private IEnumerator<T> stream;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="source">Source of the data</param>
        public IndexableCachedEnumeration(IEnumerable<T> source)
        {
            stream = source.GetEnumerator();
            listCache = new List<T>();
        }

        /// <summary>
        /// Get an item
        /// </summary>
        /// <param name="i">The index</param>
        /// <returns>Item at the index</returns>
        public T this[int i]
        {
            get
            {
                if (i < listCache.Count)
                {
                    return listCache[i];
                }
                else
                {
                    while (stream.MoveNext())
                    {
                        listCache.Add(stream.Current);
                        if (i < listCache.Count)
                        {
                            return stream.Current;
                        }
                    }
                    throw new IndexOutOfRangeException();
                }
            }
        }
    }

    /// <summary>
    /// Class to cache lazy evaluated objects from indexable sources
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class IndexableCachedConvertedCollection<S, T> where S : class where T : class
    {
        private Func<S, T> conversion;
        private IList<S> listSource;
        private S[] arraySource;
        private T[] arrayCache;

        /// <summary>
        /// Constructor for an IList source
        /// </summary>
        /// <param name="source">IList of data</param>
        /// <param name="conversion">The function which converts an item in the source to the desired type</param>
        public IndexableCachedConvertedCollection(IList<S> source, Func<S, T> conversion)
        {
            this.conversion = conversion;
            listSource = source;
            arraySource = null;
            arrayCache = new T[listSource.Count];
        }

        /// <summary>
        /// Constructor for an array source
        /// </summary>
        /// <param name="source">Array of data</param>
        /// <param name="conversion">The function which converts an item in the source to the desired type</param>
        public IndexableCachedConvertedCollection(S[] source, Func<S, T> conversion)
        {
            this.conversion = conversion;
            arraySource = source;
            listSource = null;
            arrayCache = new T[arraySource.Length];
        }

        /// <summary>
        /// Get an item
        /// </summary>
        /// <param name="i">The index</param>
        /// <returns>Item at the index</returns>
        public T this[int i]
        {
            get
            {
                if (null == arrayCache[i])
                {
                    S item = null == listSource ? arraySource[i] : listSource[i];
                    if (null != item)
                    {
                        arrayCache[i] = conversion.Invoke(item);
                    }
                }
                return arrayCache[i];
            }
        }
    }
}

  1. No comments yet.
  1. No trackbacks yet.

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: