Click here to Skip to main content

Strongly Typed Sub-Lists Which Modify Their Parent List (No Events)

Generic list wrapper that returns a smaller strongly typed sub-list which modifies the parent-list when changed, without using events
Sign Up to vote bad good
Add a reason or comment to your vote: x
Votes of 3 or less require a comment
Let's say there are two classes named "Add" and "Delete", derived from a class named "Base". We want a list of "Base" objects, but this master list can contain a mixture of any objects derived from "Base" as well. I want to be able to retrieve a strongly typed sub-list of only "Add" objects from the Master list, but if I insert or remove "Add" objects from the sub-list, I also want the master list to be modified as well without extra code, and without the slow-down and thread unsafety of events being thrown constantly. Here is the solution:
/// <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
}
 
Here is an example of how to implement the class using an XML serializable format:
 
[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; }
    }
}
Posted 27 Jan '12
Edited 5 Feb '12


This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Your Filters
Interested
Ignored
     
  1. SAKryukov (583)
  2. CRDave1988 (390)
  3. CPallini (315)
  4. Varun Sareen (308)
  1. SAKryukov (13,971)
  2. OriginalGriff (8,238)
  3. Christian Graus (7,396)
  4. thatraja (5,300)
  5. Abhinav S (5,103)

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
-- There are no messages in this forum --

Advertise | Privacy | Mobile
Web04 | 2.5.120222.1 | Last Updated 5 Feb 2012
Copyright © CodeProject, 1999-2012
All Rights Reserved. Terms of Use
Layout: fixed | fluid