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





5.00/5 (1 vote)
Generic list wrapper that returns a smaller strongly typed sub-list which modifies the parent-list when changed, without using events
Introduction
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 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 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; }
}
}