The Labs \ Source Viewer \ SSCLI \ System.Collections.Specialized \ KeysCollection

  1. //------------------------------------------------------------------------------
  2. // <copyright file="NameObjectCollectionBase.cs" company="Microsoft">
  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. // </copyright>
  14. //------------------------------------------------------------------------------
  15. /*
  16. * Ordered String/Object collection of name/value pairs with support for null key
  17. *
  18. * This class is intended to be used as a base class
  19. *
  20. * Copyright (c) 2000 Microsoft Corporation
  21. */
  22. namespace System.Collections.Specialized
  23. {
  24.    
  25.     using Microsoft.Win32;
  26.     using System.Collections;
  27.     using System.Runtime.Serialization;
  28.     using System.Globalization;
  29.     using System.Security.Permissions;
  30.    
  31.     /// <devdoc>
  32.     /// <para>Provides the <see langword='abstract '/>base class for a sorted collection of associated <see cref='System.String' qualify='true'/> keys
  33.     /// and <see cref='System.Object' qualify='true'/> values that can be accessed either with the hash code of
  34.     /// the key or with the index.</para>
  35.     /// </devdoc>
  36.     [Serializable()]
  37.     public abstract class NameObjectCollectionBase : ICollection, ISerializable, IDeserializationCallback
  38.     {
  39.         // const names used for serialization
  40.         private const string ReadOnlyName = "ReadOnly";
  41.         private const string CountName = "Count";
  42.         private const string ComparerName = "Comparer";
  43.         private const string HashCodeProviderName = "HashProvider";
  44.         private const string KeysName = "Keys";
  45.         private const string ValuesName = "Values";
  46.         private const string KeyComparerName = "KeyComparer";
  47.         private const string VersionName = "Version";
  48.        
  49.         private bool _readOnly = false;
  50.         private ArrayList _entriesArray;
  51.         private IEqualityComparer _keyComparer;
  52.         private Hashtable _entriesTable;
  53.         private NameObjectEntry _nullKeyEntry;
  54.         private KeysCollection _keys;
  55.         private SerializationInfo _serializationInfo;
  56.         private int _version;
  57.         [NonSerialized()]
  58.         private object _syncRoot;
  59.        
  60.         private static StringComparer defaultComparer = StringComparer.InvariantCultureIgnoreCase;
  61.        
  62.         /// <devdoc>
  63.         /// <para> Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the default initial capacity and using the default case-insensitive hash
  64.         /// code provider and the default case-insensitive comparer.</para>
  65.         /// </devdoc>
  66.         protected NameObjectCollectionBase() : this(defaultComparer)
  67.         {
  68.         }
  69.        
  70.         protected NameObjectCollectionBase(IEqualityComparer equalityComparer)
  71.         {
  72.             _keyComparer = (equalityComparer == null) ? defaultComparer : equalityComparer;
  73.             Reset();
  74.         }
  75.        
  76.         protected NameObjectCollectionBase(Int32 capacity, IEqualityComparer equalityComparer) : this(equalityComparer)
  77.         {
  78.             Reset(capacity);
  79.         }
  80.        
  81.        
  82.         /// <devdoc>
  83.         /// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with
  84.         /// the default initial capacity and using the specified case-insensitive hash code provider and the
  85.         /// specified case-insensitive comparer.</para>
  86.         /// </devdoc>
  87.        
  88.         #pragma warning disable 618
  89.         [Obsolete("Please use NameObjectCollectionBase(IEqualityComparer) instead.")]
  90.         protected NameObjectCollectionBase(IHashCodeProvider hashProvider, IComparer comparer)
  91.         {
  92.             _keyComparer = new CompatibleComparer(comparer, hashProvider);
  93.             Reset();
  94.         }
  95.         #pragma warning restore 618
  96.        
  97.         /// <devdoc>
  98.         /// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the specified
  99.         /// initial capacity and using the specified case-insensitive hash code provider
  100.         /// and the specified case-insensitive comparer.</para>
  101.         /// </devdoc>
  102.         #pragma warning disable 618
  103.         [Obsolete("Please use NameObjectCollectionBase(Int32, IEqualityComparer) instead.")]
  104.         protected NameObjectCollectionBase(int capacity, IHashCodeProvider hashProvider, IComparer comparer)
  105.         {
  106.             _keyComparer = new CompatibleComparer(comparer, hashProvider);
  107.             Reset(capacity);
  108.         }
  109.         #pragma warning restore 618
  110.        
  111.         /// <devdoc>
  112.         /// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the specified
  113.         /// initial capacity and using the default case-insensitive hash code provider
  114.         /// and the default case-insensitive comparer.</para>
  115.         /// </devdoc>
  116.         protected NameObjectCollectionBase(int capacity)
  117.         {
  118.             _keyComparer = StringComparer.InvariantCultureIgnoreCase;
  119.             Reset(capacity);
  120.         }
  121.        
  122.         // Allow internal extenders to avoid creating the hashtable/arraylist.
  123.         internal NameObjectCollectionBase(DBNull dummy)
  124.         {
  125.         }
  126.        
  127.         //
  128.         // Serialization support
  129.         //
  130.        
  131.         /// <devdoc>
  132.         /// <para>[To be supplied.]</para>
  133.         /// </devdoc>
  134.         protected NameObjectCollectionBase(SerializationInfo info, StreamingContext context)
  135.         {
  136.             _serializationInfo = info;
  137.         }
  138.        
  139.         /// <devdoc>
  140.         /// <para>[To be supplied.]</para>
  141.         /// </devdoc>
  142.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  143.         public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  144.         {
  145.             if (info == null)
  146.                 throw new ArgumentNullException("info");
  147.            
  148.             info.AddValue(ReadOnlyName, _readOnly);
  149.            
  150.             #pragma warning disable 618
  151.             // Maintain backward serialization compatibility if new APIs are not used.
  152.             if (_keyComparer == defaultComparer) {
  153.                 info.AddValue(HashCodeProviderName, CompatibleComparer.DefaultHashCodeProvider, typeof(IHashCodeProvider));
  154.                 info.AddValue(ComparerName, CompatibleComparer.DefaultComparer, typeof(IComparer));
  155.             }
  156.             else if (_keyComparer == null) {
  157.                 info.AddValue(HashCodeProviderName, null, typeof(IHashCodeProvider));
  158.                 info.AddValue(ComparerName, null, typeof(IComparer));
  159.             }
  160.             else if (_keyComparer is CompatibleComparer) {
  161.                 CompatibleComparer c = (CompatibleComparer)_keyComparer;
  162.                 info.AddValue(HashCodeProviderName, c.HashCodeProvider, typeof(IHashCodeProvider));
  163.                 info.AddValue(ComparerName, c.Comparer, typeof(IComparer));
  164.             }
  165.             else {
  166.                 info.AddValue(KeyComparerName, _keyComparer, typeof(IEqualityComparer));
  167.             }
  168.             #pragma warning restore 618
  169.            
  170.             int count = _entriesArray.Count;
  171.             info.AddValue(CountName, count);
  172.            
  173.             string[] keys = new string[count];
  174.             object[] values = new object[count];
  175.            
  176.             for (int i = 0; i < count; i++) {
  177.                 NameObjectEntry entry = (NameObjectEntry)_entriesArray[i];
  178.                 keys[i] = entry.Key;
  179.                 values[i] = entry.Value;
  180.             }
  181.            
  182.             info.AddValue(KeysName, keys, typeof(string[]));
  183.             info.AddValue(ValuesName, values, typeof(object[]));
  184.             info.AddValue(VersionName, _version);
  185.         }
  186.        
  187.         /// <devdoc>
  188.         /// <para>[To be supplied.]</para>
  189.         /// </devdoc>
  190.         public virtual void OnDeserialization(object sender)
  191.         {
  192.             if (_keyComparer != null) {
  193.                 return;
  194.                 //Somebody had a dependency on this hashtable and fixed us up before the ObjectManager got to it.
  195.             }
  196.            
  197.             if (_serializationInfo == null)
  198.                 throw new SerializationException();
  199.            
  200.             SerializationInfo info = _serializationInfo;
  201.             _serializationInfo = null;
  202.            
  203.             bool readOnly = false;
  204.             int count = 0;
  205.             string[] keys = null;
  206.             object[] values = null;
  207.             #pragma warning disable 618
  208.             IHashCodeProvider hashProvider = null;
  209.             #pragma warning restore 618
  210.             IComparer comparer = null;
  211.             bool hasVersion = false;
  212.             int serializedVersion = 0;
  213.            
  214.             SerializationInfoEnumerator enumerator = info.GetEnumerator();
  215.             while (enumerator.MoveNext()) {
  216.                 switch (enumerator.Name) {
  217.                     case ReadOnlyName:
  218.                         readOnly = info.GetBoolean(ReadOnlyName);
  219.                         ;
  220.                         break;
  221.                     case HashCodeProviderName:
  222.                         #pragma warning disable 618
  223.                         hashProvider = (IHashCodeProvider)info.GetValue(HashCodeProviderName, typeof(IHashCodeProvider));
  224.                         ;
  225.                         #pragma warning restore 618
  226.                         break;
  227.                     case ComparerName:
  228.                         comparer = (IComparer)info.GetValue(ComparerName, typeof(IComparer));
  229.                         break;
  230.                     case KeyComparerName:
  231.                         _keyComparer = (IEqualityComparer)info.GetValue(KeyComparerName, typeof(IEqualityComparer));
  232.                         break;
  233.                     case CountName:
  234.                         count = info.GetInt32(CountName);
  235.                         break;
  236.                     case KeysName:
  237.                         keys = (string[])info.GetValue(KeysName, typeof(string[]));
  238.                         break;
  239.                     case ValuesName:
  240.                         values = (object[])info.GetValue(ValuesName, typeof(object[]));
  241.                         break;
  242.                     case VersionName:
  243.                         hasVersion = true;
  244.                         serializedVersion = info.GetInt32(VersionName);
  245.                         break;
  246.                 }
  247.             }
  248.            
  249.             if (_keyComparer == null) {
  250.                 if (comparer == null || hashProvider == null) {
  251.                     throw new SerializationException();
  252.                 }
  253.                 else {
  254.                     // create a new key comparer for V1 Object
  255.                     _keyComparer = new CompatibleComparer(comparer, hashProvider);
  256.                 }
  257.             }
  258.            
  259.             if (keys == null || values == null)
  260.                 throw new SerializationException();
  261.            
  262.             Reset(count);
  263.            
  264.             for (int i = 0; i < count; i++)
  265.                 BaseAdd(keys[i], values[i]);
  266.            
  267.             _readOnly = readOnly;
  268.             // after collection populated
  269.             if (hasVersion) {
  270.                 _version = serializedVersion;
  271.             }
  272.         }
  273.        
  274.         //
  275.         // Private helpers
  276.         //
  277.        
  278.         private void Reset()
  279.         {
  280.             _entriesArray = new ArrayList();
  281.             _entriesTable = new Hashtable(_keyComparer);
  282.             _nullKeyEntry = null;
  283.             _version++;
  284.         }
  285.        
  286.         private void Reset(int capacity)
  287.         {
  288.             _entriesArray = new ArrayList(capacity);
  289.             _entriesTable = new Hashtable(capacity, _keyComparer);
  290.             _nullKeyEntry = null;
  291.             _version++;
  292.         }
  293.        
  294.         private NameObjectEntry FindEntry(string key)
  295.         {
  296.             if (key != null)
  297.                 return (NameObjectEntry)_entriesTable[key];
  298.             else
  299.                 return _nullKeyEntry;
  300.         }
  301.        
  302.         internal IEqualityComparer Comparer {
  303.             get { return _keyComparer; }
  304.             set { _keyComparer = value; }
  305.         }
  306.        
  307.        
  308.        
  309.         /// <devdoc>
  310.         /// <para>Gets or sets a value indicating whether the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance is read-only.</para>
  311.         /// </devdoc>
  312.         protected bool IsReadOnly {
  313.             get { return _readOnly; }
  314.             set { _readOnly = value; }
  315.         }
  316.        
  317.         /// <devdoc>
  318.         /// <para>Gets a value indicating whether the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance contains entries whose
  319.         /// keys are not <see langword='null'/>.</para>
  320.         /// </devdoc>
  321.         protected bool BaseHasKeys()
  322.         {
  323.             return (_entriesTable.Count > 0);
  324.             // any entries with keys?
  325.         }
  326.        
  327.         //
  328.         // Methods to add / remove entries
  329.         //
  330.        
  331.         /// <devdoc>
  332.         /// <para>Adds an entry with the specified key and value into the
  333.         /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  334.         /// </devdoc>
  335.         protected void BaseAdd(string name, object value)
  336.         {
  337.             if (_readOnly)
  338.                 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
  339.            
  340.             NameObjectEntry entry = new NameObjectEntry(name, value);
  341.            
  342.             // insert entry into hashtable
  343.             if (name != null) {
  344.                 if (_entriesTable[name] == null)
  345.                     _entriesTable.Add(name, entry);
  346.             }
  347.             else {
  348.                 // null key -- special case -- hashtable doesn't like null keys
  349.                 if (_nullKeyEntry == null)
  350.                     _nullKeyEntry = entry;
  351.             }
  352.            
  353.             // add entry to the list
  354.             _entriesArray.Add(entry);
  355.            
  356.             _version++;
  357.         }
  358.        
  359.         /// <devdoc>
  360.         /// <para>Removes the entries with the specified key from the
  361.         /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  362.         /// </devdoc>
  363.         protected void BaseRemove(string name)
  364.         {
  365.             if (_readOnly)
  366.                 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
  367.            
  368.             if (name != null) {
  369.                 // remove from hashtable
  370.                 _entriesTable.Remove(name);
  371.                
  372.                 // remove from array
  373.                 for (int i = _entriesArray.Count - 1; i >= 0; i--) {
  374.                     if (_keyComparer.Equals(name, BaseGetKey(i)))
  375.                         _entriesArray.RemoveAt(i);
  376.                 }
  377.             }
  378.             else {
  379.                 // null key -- special case
  380.                 // null out special 'null key' entry
  381.                 _nullKeyEntry = null;
  382.                
  383.                 // remove from array
  384.                 for (int i = _entriesArray.Count - 1; i >= 0; i--) {
  385.                     if (BaseGetKey(i) == null)
  386.                         _entriesArray.RemoveAt(i);
  387.                 }
  388.             }
  389.            
  390.             _version++;
  391.         }
  392.        
  393.         /// <devdoc>
  394.         /// <para> Removes the entry at the specified index of the
  395.         /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  396.         /// </devdoc>
  397.         protected void BaseRemoveAt(int index)
  398.         {
  399.             if (_readOnly)
  400.                 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
  401.            
  402.             string key = BaseGetKey(index);
  403.            
  404.             if (key != null) {
  405.                 // remove from hashtable
  406.                 _entriesTable.Remove(key);
  407.             }
  408.             else {
  409.                 // null key -- special case
  410.                 // null out special 'null key' entry
  411.                 _nullKeyEntry = null;
  412.             }
  413.            
  414.             // remove from array
  415.             _entriesArray.RemoveAt(index);
  416.            
  417.             _version++;
  418.         }
  419.        
  420.         /// <devdoc>
  421.         /// <para>Removes all entries from the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  422.         /// </devdoc>
  423.         protected void BaseClear()
  424.         {
  425.             if (_readOnly)
  426.                 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
  427.            
  428.             Reset();
  429.         }
  430.        
  431.         //
  432.         // Access by name
  433.         //
  434.        
  435.         /// <devdoc>
  436.         /// <para>Gets the value of the first entry with the specified key from
  437.         /// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  438.         /// </devdoc>
  439.         protected object BaseGet(string name)
  440.         {
  441.             NameObjectEntry e = FindEntry(name);
  442.             return (e != null) ? e.Value : null;
  443.         }
  444.        
  445.         /// <devdoc>
  446.         /// <para>Sets the value of the first entry with the specified key in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>
  447.         /// instance, if found; otherwise, adds an entry with the specified key and value
  448.         /// into the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>
  449.         /// instance.</para>
  450.         /// </devdoc>
  451.         protected void BaseSet(string name, object value)
  452.         {
  453.             if (_readOnly)
  454.                 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
  455.            
  456.             NameObjectEntry entry = FindEntry(name);
  457.             if (entry != null) {
  458.                 entry.Value = value;
  459.                 _version++;
  460.             }
  461.             else {
  462.                 BaseAdd(name, value);
  463.             }
  464.         }
  465.        
  466.         //
  467.         // Access by index
  468.         //
  469.        
  470.         /// <devdoc>
  471.         /// <para>Gets the value of the entry at the specified index of
  472.         /// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  473.         /// </devdoc>
  474.         protected object BaseGet(int index)
  475.         {
  476.             NameObjectEntry entry = (NameObjectEntry)_entriesArray[index];
  477.             return entry.Value;
  478.         }
  479.        
  480.         /// <devdoc>
  481.         /// <para>Gets the key of the entry at the specified index of the
  482.         /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>
  483.         /// instance.</para>
  484.         /// </devdoc>
  485.         protected string BaseGetKey(int index)
  486.         {
  487.             NameObjectEntry entry = (NameObjectEntry)_entriesArray[index];
  488.             return entry.Key;
  489.         }
  490.        
  491.         /// <devdoc>
  492.         /// <para>Sets the value of the entry at the specified index of
  493.         /// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  494.         /// </devdoc>
  495.         protected void BaseSet(int index, object value)
  496.         {
  497.             if (_readOnly)
  498.                 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
  499.            
  500.             NameObjectEntry entry = (NameObjectEntry)_entriesArray[index];
  501.             entry.Value = value;
  502.             _version++;
  503.         }
  504.        
  505.         //
  506.         // ICollection implementation
  507.         //
  508.        
  509.         /// <devdoc>
  510.         /// <para>Returns an enumerator that can iterate through the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>.</para>
  511.         /// </devdoc>
  512.         public virtual IEnumerator GetEnumerator()
  513.         {
  514.             return new NameObjectKeysEnumerator(this);
  515.         }
  516.        
  517.         /// <devdoc>
  518.         /// <para>Gets the number of key-and-value pairs in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  519.         /// </devdoc>
  520.         public virtual int Count {
  521.             get { return _entriesArray.Count; }
  522.         }
  523.        
  524.         void ICollection.CopyTo(Array array, int index)
  525.         {
  526.             if (array == null) {
  527.                 throw new ArgumentNullException("array");
  528.             }
  529.            
  530.             if (array.Rank != 1) {
  531.                 throw new ArgumentException(SR.GetString(SR.Arg_MultiRank));
  532.             }
  533.            
  534.             if (index < 0) {
  535.                 throw new ArgumentOutOfRangeException("index", SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)));
  536.             }
  537.            
  538.             if (array.Length - index < _entriesArray.Count) {
  539.                 throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
  540.             }
  541.            
  542.             for (IEnumerator e = this.GetEnumerator(); e.MoveNext();)
  543.                 array.SetValue(e.Current, index++);
  544.         }
  545.        
  546.         object ICollection.SyncRoot {
  547.             get {
  548.                 if (_syncRoot == null) {
  549.                     System.Threading.Interlocked.CompareExchange(ref _syncRoot, new object(), null);
  550.                 }
  551.                 return _syncRoot;
  552.             }
  553.         }
  554.        
  555.         bool ICollection.IsSynchronized {
  556.             get { return false; }
  557.         }
  558.        
  559.         //
  560.         // Helper methods to get arrays of keys and values
  561.         //
  562.        
  563.         /// <devdoc>
  564.         /// <para>Returns a <see cref='System.String' qualify='true'/> array containing all the keys in the
  565.         /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  566.         /// </devdoc>
  567.         protected string[] BaseGetAllKeys()
  568.         {
  569.             int n = _entriesArray.Count;
  570.             string[] allKeys = new string[n];
  571.            
  572.             for (int i = 0; i < n; i++)
  573.                 allKeys[i] = BaseGetKey(i);
  574.            
  575.             return allKeys;
  576.         }
  577.        
  578.         /// <devdoc>
  579.         /// <para>Returns an <see cref='System.Object' qualify='true'/> array containing all the values in the
  580.         /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  581.         /// </devdoc>
  582.         protected object[] BaseGetAllValues()
  583.         {
  584.             int n = _entriesArray.Count;
  585.             object[] allValues = new object[n];
  586.            
  587.             for (int i = 0; i < n; i++)
  588.                 allValues[i] = BaseGet(i);
  589.            
  590.             return allValues;
  591.         }
  592.        
  593.         /// <devdoc>
  594.         /// <para>Returns an array of the specified type containing
  595.         /// all the values in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  596.         /// </devdoc>
  597.         protected object[] BaseGetAllValues(Type type)
  598.         {
  599.             int n = _entriesArray.Count;
  600.             object[] allValues = (object[])Array.CreateInstance(type, n);
  601.            
  602.             for (int i = 0; i < n; i++) {
  603.                 allValues[i] = BaseGet(i);
  604.             }
  605.            
  606.             return allValues;
  607.         }
  608.        
  609.         //
  610.         // Keys propetry
  611.         //
  612.        
  613.         /// <devdoc>
  614.         /// <para>Returns a <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/> instance containing
  615.         /// all the keys in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
  616.         /// </devdoc>
  617.         public virtual KeysCollection Keys {
  618.             get {
  619.                 if (_keys == null)
  620.                     _keys = new KeysCollection(this);
  621.                 return _keys;
  622.             }
  623.         }
  624.        
  625.         //
  626.         // Simple entry class to allow substitution of values and indexed access to keys
  627.         //
  628.        
  629.         internal class NameObjectEntry
  630.         {
  631.            
  632.             internal NameObjectEntry(string name, object value)
  633.             {
  634.                 Key = name;
  635.                 Value = value;
  636.             }
  637.            
  638.             internal string Key;
  639.             internal object Value;
  640.         }
  641.        
  642.         //
  643.         // Enumerator over keys of NameObjectCollection
  644.         //
  645.        
  646.         [Serializable()]
  647.         internal class NameObjectKeysEnumerator : IEnumerator
  648.         {
  649.             private int _pos;
  650.             private NameObjectCollectionBase _coll;
  651.             private int _version;
  652.            
  653.             internal NameObjectKeysEnumerator(NameObjectCollectionBase coll)
  654.             {
  655.                 _coll = coll;
  656.                 _version = _coll._version;
  657.                 _pos = -1;
  658.             }
  659.            
  660.             public bool MoveNext()
  661.             {
  662.                 if (_version != _coll._version)
  663.                     throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
  664.                
  665.                 if (_pos < _coll.Count - 1) {
  666.                     _pos++;
  667.                     return true;
  668.                 }
  669.                 else {
  670.                     _pos = _coll.Count;
  671.                     return false;
  672.                 }
  673.                
  674.             }
  675.            
  676.             public void Reset()
  677.             {
  678.                 if (_version != _coll._version)
  679.                     throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
  680.                 _pos = -1;
  681.             }
  682.            
  683.             public object Current {
  684.                 get {
  685.                     if (_pos >= 0 && _pos < _coll.Count) {
  686.                         return _coll.BaseGetKey(_pos);
  687.                     }
  688.                     else {
  689.                         throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
  690.                     }
  691.                 }
  692.             }
  693.         }
  694.        
  695.         //
  696.         // Keys collection
  697.         //
  698.        
  699.         /// <devdoc>
  700.         /// <para>Represents a collection of the <see cref='System.String' qualify='true'/> keys of a collection.</para>
  701.         /// </devdoc>
  702.         [Serializable()]
  703.         public class KeysCollection : ICollection
  704.         {
  705.            
  706.             private NameObjectCollectionBase _coll;
  707.            
  708.             internal KeysCollection(NameObjectCollectionBase coll)
  709.             {
  710.                 _coll = coll;
  711.             }
  712.            
  713.             // Indexed access
  714.            
  715.             /// <devdoc>
  716.             /// <para> Gets the key at the specified index of the collection.</para>
  717.             /// </devdoc>
  718.             public virtual string Get(int index)
  719.             {
  720.                 return _coll.BaseGetKey(index);
  721.             }
  722.            
  723.             /// <devdoc>
  724.             /// <para>Represents the entry at the specified index of the collection.</para>
  725.             /// </devdoc>
  726.             public string this[int index]
  727.             {
  728.                 get { return Get(index); }
  729.             }
  730.            
  731.             // ICollection implementation
  732.            
  733.             /// <devdoc>
  734.             /// <para>Returns an enumerator that can iterate through the
  735.             /// <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/>.</para>
  736.             /// </devdoc>
  737.             public IEnumerator GetEnumerator()
  738.             {
  739.                 return new NameObjectKeysEnumerator(_coll);
  740.             }
  741.            
  742.             /// <devdoc>
  743.             /// <para>Gets the number of keys in the <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/>.</para>
  744.             /// </devdoc>
  745.             public int Count {
  746.                 get { return _coll.Count; }
  747.             }
  748.            
  749.             void ICollection.CopyTo(Array array, int index)
  750.             {
  751.                 if (array == null) {
  752.                     throw new ArgumentNullException("array");
  753.                 }
  754.                
  755.                 if (array.Rank != 1) {
  756.                     throw new ArgumentException(SR.GetString(SR.Arg_MultiRank));
  757.                 }
  758.                
  759.                 if (index < 0) {
  760.                     throw new ArgumentOutOfRangeException("index", SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)));
  761.                 }
  762.                
  763.                 if (array.Length - index < _coll.Count) {
  764.                     throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
  765.                 }
  766.                
  767.                 for (IEnumerator e = this.GetEnumerator(); e.MoveNext();)
  768.                     array.SetValue(e.Current, index++);
  769.             }
  770.            
  771.             object ICollection.SyncRoot {
  772.                 get { return ((ICollection)_coll).SyncRoot; }
  773.             }
  774.            
  775.            
  776.             bool ICollection.IsSynchronized {
  777.                 get { return false; }
  778.             }
  779.         }
  780.     }
  781.    
  782.     [Serializable()]
  783.     internal class CompatibleComparer : IEqualityComparer
  784.     {
  785.         IComparer _comparer;
  786.         static IComparer defaultComparer;
  787.         // Needed for compatability
  788.         #pragma warning disable 618
  789.         IHashCodeProvider _hcp;
  790.        
  791.         static IHashCodeProvider defaultHashProvider;
  792.        
  793.         internal CompatibleComparer(IComparer comparer, IHashCodeProvider hashCodeProvider)
  794.         {
  795.             _comparer = comparer;
  796.             _hcp = hashCodeProvider;
  797.         }
  798.         #pragma warning restore 618
  799.        
  800.         public new bool Equals(object a, object b)
  801.         {
  802.             if (a == b)
  803.                 return true;
  804.             if (a == null || b == null)
  805.                 return false;
  806.            
  807.             // We must call Compare or CompareTo method
  808.             // to make sure everything is fine, but the
  809.             // guideline is that Equals should never throw.
  810.             // So we need to swallow ArgumentException (note this
  811.             // is the exception we should get if two objects are not
  812.             // comparable.)
  813.            
  814.             try {
  815.                 if (_comparer != null)
  816.                     return (_comparer.Compare(a, b) == 0);
  817.                
  818.                 IComparable ia = a as IComparable;
  819.                 if (ia != null)
  820.                     return (ia.CompareTo(b) == 0);
  821.             }
  822.             catch (ArgumentException) {
  823.                 return false;
  824.             }
  825.            
  826.             return a.Equals(b);
  827.         }
  828.        
  829.         public int GetHashCode(object obj)
  830.         {
  831.             if (obj == null) {
  832.                 throw new ArgumentNullException("obj");
  833.             }
  834.            
  835.             if (_hcp != null)
  836.                 return _hcp.GetHashCode(obj);
  837.             return obj.GetHashCode();
  838.         }
  839.        
  840.         public IComparer Comparer {
  841.             get { return _comparer; }
  842.         }
  843.        
  844.         #pragma warning disable 618
  845.         public IHashCodeProvider HashCodeProvider {
  846.             get { return _hcp; }
  847.         }
  848.         #pragma warning restore 618
  849.        
  850.         public static IComparer DefaultComparer {
  851.             get {
  852.                 if (defaultComparer == null) {
  853.                     defaultComparer = new CaseInsensitiveComparer(CultureInfo.InvariantCulture);
  854.                 }
  855.                 return defaultComparer;
  856.             }
  857.         }
  858.        
  859.         #pragma warning disable 618
  860.         public static IHashCodeProvider DefaultHashCodeProvider {
  861.             get {
  862.                 if (defaultHashProvider == null) {
  863.                     defaultHashProvider = new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture);
  864.                 }
  865.                 return defaultHashProvider;
  866.             }
  867.         }
  868.         #pragma warning restore 618
  869.     }
  870. }

Developer Fusion