SynchronizedKeyedCollection.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.Collections.Generic
  5. {
  6. using System;
  7. using System.Runtime;
  8. using System.Runtime.InteropServices;
  9. using System.ServiceModel;
  10. [ComVisible(false)]
  11. public abstract class SynchronizedKeyedCollection<K, T> : SynchronizedCollection<T>
  12. {
  13. const int defaultThreshold = 0;
  14. IEqualityComparer<K> comparer;
  15. Dictionary<K, T> dictionary;
  16. int keyCount;
  17. int threshold;
  18. protected SynchronizedKeyedCollection()
  19. {
  20. this.comparer = EqualityComparer<K>.Default;
  21. this.threshold = int.MaxValue;
  22. }
  23. protected SynchronizedKeyedCollection(object syncRoot)
  24. : base(syncRoot)
  25. {
  26. this.comparer = EqualityComparer<K>.Default;
  27. this.threshold = int.MaxValue;
  28. }
  29. protected SynchronizedKeyedCollection(object syncRoot, IEqualityComparer<K> comparer)
  30. : base(syncRoot)
  31. {
  32. if (comparer == null)
  33. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("comparer"));
  34. this.comparer = comparer;
  35. this.threshold = int.MaxValue;
  36. }
  37. protected SynchronizedKeyedCollection(object syncRoot, IEqualityComparer<K> comparer, int dictionaryCreationThreshold)
  38. : base(syncRoot)
  39. {
  40. if (comparer == null)
  41. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("comparer"));
  42. if (dictionaryCreationThreshold < -1)
  43. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("dictionaryCreationThreshold", dictionaryCreationThreshold,
  44. SR.GetString(SR.ValueMustBeInRange, -1, int.MaxValue)));
  45. else if (dictionaryCreationThreshold == -1)
  46. this.threshold = int.MaxValue;
  47. else
  48. this.threshold = dictionaryCreationThreshold;
  49. this.comparer = comparer;
  50. }
  51. public T this[K key]
  52. {
  53. get
  54. {
  55. if (key == null)
  56. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("key"));
  57. lock (this.SyncRoot)
  58. {
  59. if (this.dictionary != null)
  60. return this.dictionary[key];
  61. for (int i = 0; i < this.Items.Count; i++)
  62. {
  63. T item = this.Items[i];
  64. if (this.comparer.Equals(key, this.GetKeyForItem(item)))
  65. return item;
  66. }
  67. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new KeyNotFoundException());
  68. }
  69. }
  70. }
  71. protected IDictionary<K, T> Dictionary
  72. {
  73. get { return this.dictionary; }
  74. }
  75. void AddKey(K key, T item)
  76. {
  77. if (this.dictionary != null)
  78. this.dictionary.Add(key, item);
  79. else if (this.keyCount == this.threshold)
  80. {
  81. this.CreateDictionary();
  82. this.dictionary.Add(key, item);
  83. }
  84. else
  85. {
  86. if (this.Contains(key))
  87. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.CannotAddTwoItemsWithTheSameKeyToSynchronizedKeyedCollection0)));
  88. this.keyCount++;
  89. }
  90. }
  91. protected void ChangeItemKey(T item, K newKey)
  92. {
  93. // check if the item exists in the collection
  94. if (!this.ContainsItem(item))
  95. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.ItemDoesNotExistInSynchronizedKeyedCollection0)));
  96. K oldKey = this.GetKeyForItem(item);
  97. if (!this.comparer.Equals(newKey, oldKey))
  98. {
  99. if (newKey != null)
  100. this.AddKey(newKey, item);
  101. if (oldKey != null)
  102. this.RemoveKey(oldKey);
  103. }
  104. }
  105. protected override void ClearItems()
  106. {
  107. base.ClearItems();
  108. if (this.dictionary != null)
  109. this.dictionary.Clear();
  110. this.keyCount = 0;
  111. }
  112. public bool Contains(K key)
  113. {
  114. if (key == null)
  115. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("key"));
  116. lock (this.SyncRoot)
  117. {
  118. if (this.dictionary != null)
  119. return this.dictionary.ContainsKey(key);
  120. if (key != null)
  121. {
  122. for (int i = 0; i < Items.Count; i++)
  123. {
  124. T item = Items[i];
  125. if (this.comparer.Equals(key, GetKeyForItem(item)))
  126. return true;
  127. }
  128. }
  129. return false;
  130. }
  131. }
  132. bool ContainsItem(T item)
  133. {
  134. K key;
  135. if ((this.dictionary == null) || ((key = GetKeyForItem(item)) == null))
  136. return Items.Contains(item);
  137. T itemInDict;
  138. if (this.dictionary.TryGetValue(key, out itemInDict))
  139. return EqualityComparer<T>.Default.Equals(item, itemInDict);
  140. return false;
  141. }
  142. void CreateDictionary()
  143. {
  144. this.dictionary = new Dictionary<K, T>(this.comparer);
  145. foreach (T item in Items)
  146. {
  147. K key = GetKeyForItem(item);
  148. if (key != null)
  149. this.dictionary.Add(key, item);
  150. }
  151. }
  152. protected abstract K GetKeyForItem(T item);
  153. protected override void InsertItem(int index, T item)
  154. {
  155. K key = this.GetKeyForItem(item);
  156. if (key != null)
  157. this.AddKey(key, item);
  158. base.InsertItem(index, item);
  159. }
  160. public bool Remove(K key)
  161. {
  162. if (key == null)
  163. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("key"));
  164. lock (this.SyncRoot)
  165. {
  166. if (this.dictionary != null)
  167. {
  168. if (this.dictionary.ContainsKey(key))
  169. return this.Remove(this.dictionary[key]);
  170. else
  171. return false;
  172. }
  173. else
  174. {
  175. for (int i = 0; i < Items.Count; i++)
  176. {
  177. if (comparer.Equals(key, GetKeyForItem(Items[i])))
  178. {
  179. this.RemoveItem(i);
  180. return true;
  181. }
  182. }
  183. return false;
  184. }
  185. }
  186. }
  187. protected override void RemoveItem(int index)
  188. {
  189. K key = this.GetKeyForItem(this.Items[index]);
  190. if (key != null)
  191. this.RemoveKey(key);
  192. base.RemoveItem(index);
  193. }
  194. void RemoveKey(K key)
  195. {
  196. if (!(key != null))
  197. {
  198. Fx.Assert("key shouldn't be null!");
  199. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("key");
  200. }
  201. if (this.dictionary != null)
  202. this.dictionary.Remove(key);
  203. else
  204. this.keyCount--;
  205. }
  206. protected override void SetItem(int index, T item)
  207. {
  208. K newKey = this.GetKeyForItem(item);
  209. K oldKey = this.GetKeyForItem(this.Items[index]);
  210. if (this.comparer.Equals(newKey, oldKey))
  211. {
  212. if ((newKey != null) && (this.dictionary != null))
  213. this.dictionary[newKey] = item;
  214. }
  215. else
  216. {
  217. if (newKey != null)
  218. this.AddKey(newKey, item);
  219. if (oldKey != null)
  220. this.RemoveKey(oldKey);
  221. }
  222. base.SetItem(index, item);
  223. }
  224. }
  225. }