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


 / Published in: C#
 

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.

  1. /// <summary>
  2. /// A class which wraps a parent list containing mixed object types, to
  3. /// provide smaller strongly typed sub-lists of objects.
  4. /// These sub-lists can be modified, which then modifies the parent list
  5. /// concurrently (without events being triggered).
  6. /// <para>Class is serializable</para>.
  7. /// </summary>
  8. /// <typeparam name="L">Type of objects in the sub list</typeparam>
  9. /// <typeparam name="P">The type objects in the parent list
  10. /// (from which <typeparamref name="L"/> derives or implements) </typeparam>
  11. [Serializable]
  12. public sealed class SubList<L, P> : IList<L>
  13. {
  14. private List<P> _parentList;
  15. private List<L> _tempList; //memory holder (for enumeration)
  16.  
  17. /// <summary>
  18. /// For deserializer only. Do not use this constructor.
  19. /// </summary>
  20. internal protected SubList() { }
  21.  
  22. /// <summary>
  23. /// List Constructor
  24. /// </summary>
  25. /// <param name="parentList">Reference to a parent list which contains mixed objects derived from <typeparamref name="P"/></param>
  26. public SubList(ref List<P> parentList)
  27. {
  28. //construct the reference if a null value is passed
  29. if (parentList == null)
  30. parentList = new List<P>();
  31. this._parentList = parentList;
  32. }
  33.  
  34. /// <summary>
  35. /// Create a shallow copy of this sublist to a list of type <typeparamref name="L"/>
  36. /// </summary>
  37. /// <returns>A strongly typed list copy of the the objects of type <typeparamref name="L"/></returns>
  38. public List<L> ShallowCopy()
  39. {
  40. List<L> ret = new List<L>();
  41. this._parentList.ForEach(delegate(P item)
  42. {
  43. if (item is L)
  44. ret.Add((L)(object)item);
  45. });
  46. return ret;
  47. }
  48.  
  49. public L[] ToArray()
  50. {
  51. List<L> ret = this.ShallowCopy();
  52. return ret.ToArray();
  53. }
  54.  
  55. public bool IsParentValid()
  56. {
  57. return (this._parentList != null);
  58. }
  59.  
  60. public bool IsValid(L item)
  61. {
  62. return (this.IsParentValid() && item is P);
  63. }
  64.  
  65. public void Merge(List<L> list)
  66. {
  67. list.ForEach(delegate(L item)
  68. {
  69. if (IsValid(item) && !this._parentList.Contains((P)(object)item))
  70. this._parentList.Add((P)(object)item);
  71. });
  72. }
  73.  
  74. #region IList<L> Members
  75.  
  76. public int IndexOf(L item)
  77. {
  78. if (IsValid(item))
  79. return this._parentList.IndexOf((P)(object)item);
  80. return -1;
  81. }
  82.  
  83. public void Insert(int index, L item)
  84. {
  85. if (IsValid(item))
  86. this._parentList.Insert(index, (P)(object)item);
  87. }
  88.  
  89. public void RemoveAt(int index)
  90. {
  91. this._parentList.RemoveAt(index);
  92. }
  93.  
  94. public L this[int index]
  95. {
  96. get
  97. {
  98. P ret = this._parentList[index];
  99. if (ret is L)
  100. return (L)(object)ret;
  101. return default(L);
  102. }
  103. set
  104. {
  105. P set = default(P);
  106. if (index < this._parentList.Count)
  107. set = this._parentList[index];
  108. if (set is L || set != null)
  109. this._parentList[index] = (P)(object)value;
  110. }
  111. }
  112.  
  113. #endregion
  114.  
  115. #region ICollection<L> Members
  116.  
  117. public void Add(L item)
  118. {
  119. if (IsValid(item))
  120. this._parentList.Add((P)(object)item);
  121. }
  122.  
  123. public void Clear()
  124. {
  125. foreach (P item in this._parentList)
  126. if (item is L)
  127. this._parentList.Remove((P)(object)item);
  128. }
  129.  
  130. public bool Contains(L item)
  131. {
  132. if (IsValid(item))
  133. return this._parentList.Contains((P)(object)item);
  134. return false;
  135. }
  136.  
  137. public void CopyTo(L[] array, int arrayIndex)
  138. {
  139. List<L> ret = this.ShallowCopy();
  140. if (ret.Count > 0)
  141. ret.CopyTo(array, arrayIndex);
  142. }
  143.  
  144. public int Count
  145. {
  146. get
  147. {
  148. int ret = 0;
  149. foreach (P item in this._parentList)
  150. if (item is L)
  151. ret++;
  152. return ret;
  153. }
  154. }
  155.  
  156. bool ICollection<L>.IsReadOnly
  157. {
  158. get { return ((ICollection<P>)this._parentList).IsReadOnly; }
  159. }
  160.  
  161. public bool Remove(L item)
  162. {
  163. if (IsValid(item))
  164. return this._parentList.Remove((P)(object)item);
  165. return false;
  166. }
  167.  
  168. #endregion
  169.  
  170. #region IEnumerable<L> Members
  171.  
  172. IEnumerator<L> IEnumerable<L>.GetEnumerator()
  173. {
  174. this._tempList = this.ShallowCopy();
  175. return this._tempList.GetEnumerator();
  176. }
  177.  
  178. #endregion
  179.  
  180. #region IEnumerable Members
  181.  
  182. IEnumerator IEnumerable.GetEnumerator()
  183. {
  184. return this._parentList.GetEnumerator();
  185. }
  186.  
  187. #endregion
  188. }
  189.  
  190.  
  191. //example of how to implement serialization-------------------------------------
  192.  
  193. [Serializable, DesignerCategory("code")]
  194. public abstract class Base
  195. {
  196. /// <summary>
  197. /// for deserializer only
  198. /// </summary>
  199. internal Base() { }
  200. }
  201.  
  202. [Serializable, DesignerCategory("code")]
  203. [XmlType("IndexItemAdd")]
  204. public class Add : Base
  205. {
  206. /// <summary>
  207. /// for deserializer only
  208. /// </summary>
  209. internal Add() : base() { }
  210. }
  211.  
  212. [Serializable, DesignerCategory("code")]
  213. [XmlType("IndexItemDelete")]
  214. public class Delete : Base
  215. {
  216. /// <summary>
  217. /// for deserializer only
  218. /// </summary>
  219. internal Delete() : base() { }
  220. }
  221.  
  222. [Serializable()]
  223. [DesignerCategory("code")]
  224. [XmlType("IndexItem")]
  225. public class IndexItem
  226. {
  227. private List<Base> allItems;
  228. private SubList<Add, Base> indexItemAddFields;
  229. private SubList<Delete, Base> indexItemDeleteFields;
  230.  
  231. [XmlElement("IndexItemAdd")]
  232. public SubList<Add, Base> Adds
  233. {
  234. get { return this.indexItemAddFields; }
  235. set
  236. {
  237. if (value != null && value.IsParentValid())
  238. this.indexItemAddFields = value;
  239. else
  240. this.indexItemAddFields = new SubList<Add, Base>(ref allItems);
  241. }
  242. }
  243.  
  244. [XmlElement("IndexItemDelete")]
  245. public SubList<Delete, Base> Deletes
  246. {
  247. get { return this.indexItemDeleteFields; }
  248. set
  249. {
  250. if (value != null && value.IsParentValid())
  251. this.indexItemDeleteFields = value;
  252. else
  253. this.indexItemDeleteFields = new SubList<Delete, Base>(ref allItems);
  254. }
  255. }
  256.  
  257. [XmlIgnore]
  258. public List<Base> Items
  259. {
  260. get { return this.allItems; }
  261. }
  262. }

Report this snippet  

You need to login to post a comment.