The Labs \ Source Viewer \ SSCLI \ System.Collections.ObjectModel \ KeyedCollection

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System.Collections.ObjectModel
  16. {
  17.     using System;
  18.     using System.Collections.Generic;
  19.     using System.Diagnostics;
  20.    
  21.     [Serializable()]
  22.     [System.Runtime.InteropServices.ComVisible(false)]
  23.     [DebuggerTypeProxy(typeof(Mscorlib_KeyedCollectionDebugView<, >))]
  24.     [DebuggerDisplay("Count = {Count}")]
  25.     public abstract class KeyedCollection<TKey, TItem> : Collection<TItem>
  26.     {
  27.         const int defaultThreshold = 0;
  28.        
  29.         IEqualityComparer<TKey> comparer;
  30.         Dictionary<TKey, TItem> dict;
  31.         int keyCount;
  32.         int threshold;
  33.        
  34.         protected KeyedCollection() : this(null, defaultThreshold)
  35.         {
  36.         }
  37.        
  38.         protected KeyedCollection(IEqualityComparer<TKey> comparer) : this(comparer, defaultThreshold)
  39.         {
  40.         }
  41.        
  42.        
  43.         protected KeyedCollection(IEqualityComparer<TKey> comparer, int dictionaryCreationThreshold)
  44.         {
  45.             if (comparer == null) {
  46.                 comparer = EqualityComparer<TKey>.Default;
  47.             }
  48.            
  49.             if (dictionaryCreationThreshold == -1) {
  50.                 dictionaryCreationThreshold = int.MaxValue;
  51.             }
  52.            
  53.             if (dictionaryCreationThreshold < -1) {
  54.                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.dictionaryCreationThreshold, ExceptionResource.ArgumentOutOfRange_InvalidThreshold);
  55.             }
  56.            
  57.             this.comparer = comparer;
  58.             this.threshold = dictionaryCreationThreshold;
  59.         }
  60.        
  61.         public IEqualityComparer<TKey> Comparer {
  62.             get { return comparer; }
  63.         }
  64.        
  65.         public TItem this[TKey key]
  66.         {
  67.             get {
  68.                 if (key == null) {
  69.                     ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
  70.                 }
  71.                
  72.                 if (dict != null) {
  73.                     return dict[key];
  74.                 }
  75.                
  76.                 foreach (TItem item in Items) {
  77.                     if (comparer.Equals(GetKeyForItem(item), key))
  78.                         return item;
  79.                 }
  80.                
  81.                 ThrowHelper.ThrowKeyNotFoundException();
  82.                 return default(TItem);
  83.             }
  84.         }
  85.        
  86.         public bool Contains(TKey key)
  87.         {
  88.             if (key == null) {
  89.                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
  90.             }
  91.            
  92.             if (dict != null) {
  93.                 return dict.ContainsKey(key);
  94.             }
  95.            
  96.             if (key != null) {
  97.                 foreach (TItem item in Items) {
  98.                     if (comparer.Equals(GetKeyForItem(item), key))
  99.                         return true;
  100.                 }
  101.             }
  102.             return false;
  103.         }
  104.        
  105.         private bool ContainsItem(TItem item)
  106.         {
  107.             TKey key;
  108.             if ((dict == null) || ((key = GetKeyForItem(item)) == null)) {
  109.                 return Items.Contains(item);
  110.             }
  111.            
  112.             TItem itemInDict;
  113.             bool exist = dict.TryGetValue(key, out itemInDict);
  114.             if (exist) {
  115.                 return EqualityComparer<TItem>.Default.Equals(itemInDict, item);
  116.             }
  117.             return false;
  118.         }
  119.        
  120.         public bool Remove(TKey key)
  121.         {
  122.             if (key == null) {
  123.                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
  124.             }
  125.            
  126.             if (dict != null) {
  127.                 if (dict.ContainsKey(key)) {
  128.                     return Remove(dict[key]);
  129.                 }
  130.                
  131.                 return false;
  132.             }
  133.            
  134.             if (key != null) {
  135.                 for (int i = 0; i < Items.Count; i++) {
  136.                     if (comparer.Equals(GetKeyForItem(Items[i]), key)) {
  137.                         RemoveItem(i);
  138.                         return true;
  139.                     }
  140.                 }
  141.             }
  142.             return false;
  143.         }
  144.        
  145.         protected IDictionary<TKey, TItem> Dictionary {
  146.             get { return dict; }
  147.         }
  148.        
  149.         protected void ChangeItemKey(TItem item, TKey newKey)
  150.         {
  151.             // check if the item exists in the collection
  152.             if (!ContainsItem(item)) {
  153.                 ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_ItemNotExist);
  154.             }
  155.            
  156.             TKey oldKey = GetKeyForItem(item);
  157.             if (!comparer.Equals(oldKey, newKey)) {
  158.                 if (newKey != null) {
  159.                     AddKey(newKey, item);
  160.                 }
  161.                
  162.                 if (oldKey != null) {
  163.                     RemoveKey(oldKey);
  164.                 }
  165.             }
  166.         }
  167.        
  168.         protected override void ClearItems()
  169.         {
  170.             base.ClearItems();
  171.             if (dict != null) {
  172.                 dict.Clear();
  173.             }
  174.            
  175.             keyCount = 0;
  176.         }
  177.        
  178.         protected abstract TKey GetKeyForItem(TItem item);
  179.        
  180.         protected override void InsertItem(int index, TItem item)
  181.         {
  182.             TKey key = GetKeyForItem(item);
  183.             if (key != null) {
  184.                 AddKey(key, item);
  185.             }
  186.             base.InsertItem(index, item);
  187.         }
  188.        
  189.         protected override void RemoveItem(int index)
  190.         {
  191.             TKey key = GetKeyForItem(Items[index]);
  192.             if (key != null) {
  193.                 RemoveKey(key);
  194.             }
  195.             base.RemoveItem(index);
  196.         }
  197.        
  198.         protected override void SetItem(int index, TItem item)
  199.         {
  200.             TKey newKey = GetKeyForItem(item);
  201.             TKey oldKey = GetKeyForItem(Items[index]);
  202.            
  203.             if (comparer.Equals(oldKey, newKey)) {
  204.                 if (newKey != null && dict != null) {
  205.                     dict[newKey] = item;
  206.                 }
  207.             }
  208.             else {
  209.                 if (newKey != null) {
  210.                     AddKey(newKey, item);
  211.                 }
  212.                
  213.                 if (oldKey != null) {
  214.                     RemoveKey(oldKey);
  215.                 }
  216.             }
  217.             base.SetItem(index, item);
  218.         }
  219.        
  220.         private void AddKey(TKey key, TItem item)
  221.         {
  222.             if (dict != null) {
  223.                 dict.Add(key, item);
  224.             }
  225.             else if (keyCount == threshold) {
  226.                 CreateDictionary();
  227.                 dict.Add(key, item);
  228.             }
  229.             else {
  230.                 if (Contains(key)) {
  231.                     ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
  232.                 }
  233.                
  234.                 keyCount++;
  235.             }
  236.         }
  237.        
  238.         private void CreateDictionary()
  239.         {
  240.             dict = new Dictionary<TKey, TItem>(comparer);
  241.             foreach (TItem item in Items) {
  242.                 TKey key = GetKeyForItem(item);
  243.                 if (key != null) {
  244.                     dict.Add(key, item);
  245.                 }
  246.             }
  247.         }
  248.        
  249.         private void RemoveKey(TKey key)
  250.         {
  251.             BCLDebug.Assert(key != null, "key shouldn't be null!");
  252.             if (dict != null) {
  253.                 dict.Remove(key);
  254.             }
  255.             else {
  256.                 keyCount--;
  257.             }
  258.         }
  259.     }
  260. }

Developer Fusion