RefinedList.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace Wayne.Lib
  5. {
  6. /// <summary>
  7. /// A virtual list of refined objects.
  8. /// </summary>
  9. /// <typeparam name="BaseType"></typeparam>
  10. /// <typeparam name="RefinedType"></typeparam>
  11. public class RefinedList<BaseType, RefinedType> : IList<RefinedType> where RefinedType : BaseType
  12. {
  13. #region RefinedEnumerator
  14. private class RefinedEnumerator : IEnumerator<RefinedType>
  15. {
  16. private IList<BaseType> baseList;
  17. private int index;
  18. private bool invalidated;
  19. public event EventHandler OnDisposed;
  20. public RefinedEnumerator(IList<BaseType> baseList)
  21. {
  22. this.baseList = baseList;
  23. index = -1;
  24. }
  25. public RefinedType Current { get; private set; }
  26. public void Dispose()
  27. {
  28. if (OnDisposed != null)
  29. OnDisposed(this, EventArgs.Empty);
  30. }
  31. object IEnumerator.Current
  32. {
  33. get { return Current; }
  34. }
  35. public bool MoveNext()
  36. {
  37. if (invalidated)
  38. throw new InvalidOperationException("The collection was modified after the enumerator was created.");
  39. index++;
  40. if (index < baseList.Count)
  41. Current = (RefinedType)baseList[index];
  42. return (index < baseList.Count);
  43. }
  44. public void Reset()
  45. {
  46. if (invalidated)
  47. throw new InvalidOperationException("The collection was modified after the enumerator was created.");
  48. index = -1;
  49. }
  50. public void Invalidate()
  51. {
  52. invalidated = true;
  53. }
  54. }
  55. #endregion
  56. #region Fields
  57. private IList<BaseType> baseList;
  58. private List<RefinedEnumerator> refinedEnumerators = new List<RefinedEnumerator>();
  59. private object refinedEnumeratorSyncObj = new object();
  60. #endregion
  61. #region Construction
  62. /// <summary>
  63. /// Constructor.
  64. /// </summary>
  65. /// <param name="baseList">The base list (the actual list that holds the items, or even another RefinedList).</param>
  66. public RefinedList(IList<BaseType> baseList)
  67. {
  68. this.baseList = baseList;
  69. }
  70. #endregion
  71. #region Properties
  72. /// <summary>
  73. /// Gets the number of elements contained in the list.
  74. /// </summary>
  75. public int Count
  76. {
  77. get { return baseList.Count; }
  78. }
  79. /// <summary>
  80. /// Gets a value indicating whether the list is readonly.
  81. /// </summary>
  82. public bool IsReadOnly
  83. {
  84. get { return baseList.IsReadOnly; }
  85. }
  86. /// <summary>
  87. /// Gets or sets the element at the specified index.
  88. /// </summary>
  89. /// <param name="index">The zero-based index of the element to get or set.</param>
  90. /// <returns></returns>
  91. public RefinedType this[int index]
  92. {
  93. get { return (RefinedType)baseList[index]; }
  94. set { baseList[index] = value; }
  95. }
  96. #endregion
  97. #region List Methods
  98. /// <summary>
  99. /// Determines the index of a specific item in the list.
  100. /// </summary>
  101. /// <param name="item">The object to locate in the list.</param>
  102. /// <returns></returns>
  103. public int IndexOf(RefinedType item)
  104. {
  105. return baseList.IndexOf(item);
  106. }
  107. /// <summary>
  108. /// Inserts an item to the list at the specified index.
  109. /// </summary>
  110. /// <param name="index">The zero-based index at which item should be inserted.</param>
  111. /// <param name="item"></param>
  112. public void Insert(int index, RefinedType item)
  113. {
  114. baseList.Insert(index, item);
  115. InvalidateEnumerators();
  116. }
  117. /// <summary>
  118. /// Removes the list item at the specified index.
  119. /// </summary>
  120. /// <param name="index">The object to insert into the list.</param>
  121. public void RemoveAt(int index)
  122. {
  123. baseList.RemoveAt(index);
  124. InvalidateEnumerators();
  125. }
  126. /// <summary>
  127. /// Adds an item to the list.
  128. /// </summary>
  129. /// <param name="item">The object to add to the list.</param>
  130. public void Add(RefinedType item)
  131. {
  132. baseList.Add(item);
  133. InvalidateEnumerators();
  134. }
  135. /// <summary>
  136. /// Removes all items from the list.
  137. /// </summary>
  138. public void Clear()
  139. {
  140. if (baseList.Count > 0)
  141. InvalidateEnumerators();
  142. baseList.Clear();
  143. }
  144. /// <summary>
  145. /// Determines whether the list contains a specific value.
  146. /// </summary>
  147. /// <param name="item">The object to locate in the list.</param>
  148. /// <returns></returns>
  149. public bool Contains(RefinedType item)
  150. {
  151. return baseList.Contains(item);
  152. }
  153. /// <summary>
  154. /// Copies the elements of the list to an Array, starting at a particular Array index.
  155. /// </summary>
  156. /// <param name="array">The one-dimensional Array that is the destination of the elements copied from list. The Array must have zero-based indexing.</param>
  157. /// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
  158. public void CopyTo(RefinedType[] array, int arrayIndex)
  159. {
  160. for (int i = 0; i < baseList.Count; i++)
  161. array[i + arrayIndex] = (RefinedType)baseList[i];
  162. }
  163. /// <summary>
  164. /// Removes the first occurrence of a specific object from the list.
  165. /// </summary>
  166. /// <param name="item">The object to remove from the list.</param>
  167. /// <returns></returns>
  168. public bool Remove(RefinedType item)
  169. {
  170. if (baseList.Remove(item))
  171. {
  172. InvalidateEnumerators();
  173. return true;
  174. }
  175. return false;
  176. }
  177. /// <summary>
  178. /// Adds the elements of the specified collection to the end of the list.
  179. /// </summary>
  180. /// <param name="collection">The collection whose elements should be added to the end of the list. The collection itself cannot be null, but it can contain elements that are null, if type RefinedType is a reference type.</param>
  181. public void AddRange(IEnumerable<RefinedType> collection)
  182. {
  183. foreach (RefinedType item in collection)
  184. baseList.Add(item);
  185. InvalidateEnumerators();
  186. }
  187. #endregion
  188. #region Enumerator Methods
  189. /// <summary>
  190. /// Returns an enumerator that iterates through a collection.
  191. /// </summary>
  192. /// <returns></returns>
  193. IEnumerator IEnumerable.GetEnumerator()
  194. {
  195. return GetEnumerator();
  196. }
  197. /// <summary>
  198. /// Returns an enumerator that iterates through the collection.
  199. /// </summary>
  200. /// <returns></returns>
  201. public IEnumerator<RefinedType> GetEnumerator()
  202. {
  203. lock (refinedEnumeratorSyncObj)
  204. {
  205. RefinedEnumerator refinedEnumerator = new RefinedEnumerator(baseList);
  206. refinedEnumerator.OnDisposed += refinedEnumerator_OnDisposed;
  207. refinedEnumerators.Add(refinedEnumerator);
  208. return refinedEnumerator;
  209. }
  210. }
  211. private void refinedEnumerator_OnDisposed(object sender, EventArgs e)
  212. {
  213. lock (refinedEnumeratorSyncObj)
  214. {
  215. refinedEnumerators.Remove((RefinedEnumerator)sender);
  216. }
  217. }
  218. private void InvalidateEnumerators()
  219. {
  220. lock (refinedEnumeratorSyncObj)
  221. {
  222. foreach (RefinedEnumerator refinedEnumerator in refinedEnumerators)
  223. refinedEnumerator.Invalidate();
  224. }
  225. }
  226. #endregion
  227. }
  228. }