C Sharp - Custom Lazy Loading 3/22/2011 All C Sharp posts

If you're in a non ORM environment and have are thinking of building something custom to lazy-load data, here are a couple of useful classes and their intended implementation. Both of these classes were built to suite my needs and expect the lazy loading method to take the parent object as its only parameter.


Lazy<TParent, TChild>


    public class Lazy<TParent, TChild>
    {
        public Lazy(Func<TParent, TChild> func, TParent parent)
        {
            _func = func;
            _parent = parent;
        }

        bool _hasValue;
        TChild _value;
        TParent _parent;
        Func<TParent, TChild> _func;

        public TChild Value
        {
            get
            {
                if (!_hasValue)
                {
                    _value = _func(_parent);
                    _hasValue = true;
                }
                return _value;
            }
        }
    }

LazyList<TParent, TCollection>


    public class LazyList<TParent, TCollection> : IList<TCollection>
    {
        public LazyList(Func<TParent, IList<TCollection>> func, TParent parent)
        {
            _func = func;
            _parent = parent;
        }

        TParent _parent;
        Func<TParent, IList<TCollection>> _func;

        IList<TCollection> _items;
        IList<TCollection> Items
        {
            get
            {
                if (_items == null)
                    _items = _func(_parent) ?? new List<TCollection>();
                return _items;
            }
        }
        
        #region IList<TCollection> Members
        int IList<TCollection>.IndexOf(TCollection item)
        {
            return Items.IndexOf(item);
        }

        void IList<TCollection>.Insert(int index, TCollection item)
        {
            Items.Insert(index, item);
        }

        void IList<TCollection>.RemoveAt(int index)
        {
            Items.RemoveAt(index);
        }

        TCollection IList<TCollection>.this[int index]
        {
            get { return Items[index]; }
            set { Items[index] = value; }
        }
        #endregion

        #region ICollection<TCollection> Members
        void ICollection<TCollection>.Add(TCollection item)
        {
            Items.Add(item);
        }

        void ICollection<TCollection>.Clear()
        {
            Items.Clear();
        }

        bool ICollection<TCollection>.Contains(TCollection item)
        {
            return Items.Contains(item);
        }

        void ICollection<TCollection>.CopyTo(TCollection[] array, int arrayIndex)
        {
            Items.CopyTo(array, arrayIndex);
        }

        int ICollection<TCollection>.Count
        {
            get { return Items.Count; }
        }

        bool ICollection<TCollection>.IsReadOnly
        {
            get { return Items.IsReadOnly; }
        }

        bool ICollection<TCollection>.Remove(TCollection item)
        {
            return Items.Remove(item);
        }
        #endregion

        #region IEnumerable<TCollection> Members
        IEnumerator<TCollection> IEnumerable<TCollection>.GetEnumerator()
        {
            return Items.GetEnumerator();
        }
        #endregion

        #region IEnumerable Members
        IEnumerator IEnumerable.GetEnumerator()
        {
            return Items.GetEnumerator();
        }
        #endregion
    }

Usage



    myObject.SomeLazy = new Lazy<MyObjectType, SomeLazyType>(GetSomeLazy, myObject);

    myObject.SomeList = new LazyList<MyObjectType, OtherObjectType>(
        SomeMethodThatTakes, myObject);