Return to Snippet

Revision: 22809
at January 22, 2010 19:24 by bryanlyman


Initial Code
/// <summary>
/// A class which wraps a parent list containing mixed object types, to
/// provide smaller strongly typed sub-lists of objects.
/// These sub-lists can be modified, which then modifies the parent list
/// concurrently (without events being triggered).
/// <para>Class is serializable</para>.
/// </summary>
/// <typeparam name="L">Type of objects in the sub list</typeparam>
/// <typeparam name="P">The type objects in the parent list
/// (from which <typeparamref name="L"/> derives or implements) </typeparam>
[Serializable]
public sealed class SubList<L, P> : IList<L>
{
    private List<P> _parentList;
    private List<L> _tempList; //memory holder (for enumeration)

    /// <summary>
    /// For deserializer only. Do not use this constructor.
    /// </summary>
    internal protected SubList() { }

    /// <summary>
    /// List Constructor
    /// </summary>
    /// <param name="parentList">Reference to a parent list which contains mixed objects derived from <typeparamref name="P"/></param>        
    public SubList(ref List<P> parentList)
    {
        //construct the reference if a null value is passed
        if (parentList == null)
            parentList = new List<P>();
        this._parentList = parentList;
    }

    /// <summary>
    /// Create a shallow copy of this sublist to a list of type <typeparamref name="L"/>
    /// </summary>
    /// <returns>A strongly typed list copy of the the objects of type <typeparamref name="L"/></returns>
    public List<L> ShallowCopy()
    {
        List<L> ret = new List<L>();
        this._parentList.ForEach(delegate(P item)
        {
            if (item is L)
                ret.Add((L)(object)item);
        });
        return ret;
    }

    public L[] ToArray()
    {
        List<L> ret = this.ShallowCopy();
        return ret.ToArray();
    }

    public bool IsParentValid()
    {
        return (this._parentList != null);
    }

    public bool IsValid(L item)
    {
        return (this.IsParentValid() && item is P);
    }

    public void Merge(List<L> list)
    {
        list.ForEach(delegate(L item)
        {
            if (IsValid(item) && !this._parentList.Contains((P)(object)item))
                this._parentList.Add((P)(object)item);
        });
    }

    #region IList<L> Members

    public int IndexOf(L item)
    {
        if (IsValid(item))
            return this._parentList.IndexOf((P)(object)item);
        return -1;
    }

    public void Insert(int index, L item)
    {
        if (IsValid(item))
            this._parentList.Insert(index, (P)(object)item);
    }

    public void RemoveAt(int index)
    {
        this._parentList.RemoveAt(index);
    }

    public L this[int index]
    {
        get
        {
            P ret = this._parentList[index];
            if (ret is L)
                return (L)(object)ret;
            return default(L);
        }
        set
        {
            P set = default(P);
            if (index < this._parentList.Count)
                set = this._parentList[index];
            if (set is L || set != null)
                this._parentList[index] = (P)(object)value;
        }
    }

    #endregion

    #region ICollection<L> Members

    public void Add(L item)
    {
        if (IsValid(item))
            this._parentList.Add((P)(object)item);
    }

    public void Clear()
    {
        foreach (P item in this._parentList)
            if (item is L)
                this._parentList.Remove((P)(object)item);
    }

    public bool Contains(L item)
    {
        if (IsValid(item))
            return this._parentList.Contains((P)(object)item);
        return false;
    }

    public void CopyTo(L[] array, int arrayIndex)
    {
        List<L> ret = this.ShallowCopy();
        if (ret.Count > 0)
            ret.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get
        {
            int ret = 0;
            foreach (P item in this._parentList)
                if (item is L)
                    ret++;
            return ret;
        }
    }

    bool ICollection<L>.IsReadOnly
    {
        get { return ((ICollection<P>)this._parentList).IsReadOnly; }
    }

    public bool Remove(L item)
    {
        if (IsValid(item))
            return this._parentList.Remove((P)(object)item);
        return false;
    }

    #endregion

    #region IEnumerable<L> Members

    IEnumerator<L> IEnumerable<L>.GetEnumerator()
    {
        this._tempList = this.ShallowCopy();
        return this._tempList.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this._parentList.GetEnumerator();
    }

    #endregion
}


//example of how to implement serialization-------------------------------------

[Serializable, DesignerCategory("code")]
public abstract class Base
{   
    /// <summary>
    /// for deserializer only
    /// </summary>
    internal Base() { }
}

[Serializable, DesignerCategory("code")]
[XmlType("IndexItemAdd")]
public class Add : Base
{    
    /// <summary>
    /// for deserializer only
    /// </summary>
    internal Add() : base() { }
}

[Serializable, DesignerCategory("code")]
[XmlType("IndexItemDelete")]
public class Delete : Base
{
    /// <summary>
    /// for deserializer only
    /// </summary>
    internal Delete() : base() { }
}

[Serializable()]
[DesignerCategory("code")]
[XmlType("IndexItem")]
public class IndexItem
{
    private List<Base> allItems;
    private SubList<Add, Base> indexItemAddFields;
    private SubList<Delete, Base> indexItemDeleteFields;

    [XmlElement("IndexItemAdd")]
    public SubList<Add, Base> Adds
    {
        get { return this.indexItemAddFields; }
        set
        {
            if (value != null && value.IsParentValid())
                this.indexItemAddFields = value;
            else
                this.indexItemAddFields = new SubList<Add, Base>(ref allItems);
        }
    }

    [XmlElement("IndexItemDelete")]
    public SubList<Delete, Base> Deletes
    {
        get { return this.indexItemDeleteFields; }
        set
        {
            if (value != null && value.IsParentValid())
                this.indexItemDeleteFields = value;
            else
                this.indexItemDeleteFields = new SubList<Delete, Base>(ref allItems);
        }
    }

    [XmlIgnore]
    public List<Base> Items
    {
        get { return this.allItems; }
    }
}

Initial URL


Initial Description
A class which wraps a parent list containing mixed object types, to provide smaller strongly typed sub-lists of objects. These sub-lists can be modified, which then modifies the parent list concurrently (without events being triggered). Supports the merging of other lists of the same type. Supports serialization. Supports parent list auto-instantiation.

Initial Title
Generic list wrapper returns a smaller strongly typed sub-list  which modifies the parent-list when changed (without events)

Initial Tags
list, object, array

Initial Language
C#