Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System / System.Collections.Specialized / NameObjectCollectionBase.cs
index 8b1ca2248f994eac9df6aec3266cfc0eadbcd519..a1a377da08f34a0e6090892905d848c419d1ba71 100644 (file)
 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
 //
 // (C) Ximian, Inc.  http://www.ximian.com
-//\r
-\r
-using System;\r
-using System.Collections;\r
-using System.Runtime.Serialization;\r
-\r
-namespace System.Collections.Specialized\r
-{\r
-       [Serializable]\r
-       public abstract class NameObjectCollectionBase : ICollection, IEnumerable, ISerializable, IDeserializationCallback\r
-       {\r
-               private Hashtable m_ItemsContainer;\r
-               /// <summary>\r
-               /// Extends Hashtable based Items container to support storing null-key pairs\r
-               /// </summary>\r
-               private _Item m_NullKeyItem;\r
-               private ArrayList m_ItemsArray;\r
-               private IHashCodeProvider m_hashprovider;\r
-               private IComparer m_comparer;\r
-               private int m_defCapacity;\r
-               private bool m_readonly;\r
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Runtime.Serialization;
+
+namespace System.Collections.Specialized
+{
+       [Serializable]
+       public abstract class NameObjectCollectionBase : ICollection, IEnumerable, ISerializable, IDeserializationCallback
+       {
+               private Hashtable m_ItemsContainer;
+               /// <summary>
+               /// Extends Hashtable based Items container to support storing null-key pairs
+               /// </summary>
+               private _Item m_NullKeyItem;
+               private ArrayList m_ItemsArray;
+               private IHashCodeProvider m_hashprovider;
+               private IComparer m_comparer;
+               private int m_defCapacity;
+               private bool m_readonly;
                SerializationInfo infoCopy;
-\r
-               internal IComparer Comparer {\r
-                       get {return m_comparer;}\r
-               }\r
-\r
-               internal IHashCodeProvider HashCodeProvider {\r
-                       get {return m_hashprovider;}\r
-               }\r
-\r
-               internal class _Item\r
-               {\r
-                       public string key;\r
-                       public object value;\r
-                       public _Item(string key, object value)\r
-                       {\r
-                               this.key = key;\r
-                               this.value = value;\r
-                       }\r
-               }               \r
-               /// <summary>\r
-               /// Implements IEnumerable interface for KeysCollection\r
-               /// </summary>\r
-               [Serializable]\r
-               internal class _KeysEnumerator : IEnumerator\r
-               {\r
-                       private NameObjectCollectionBase m_collection;\r
-                       private int m_position;\r
-                       /*private*/internal _KeysEnumerator(NameObjectCollectionBase collection)\r
-                       {\r
-                               m_collection = collection;\r
-                               Reset();\r
-                       }\r
-                       public object Current \r
-                       {\r
-                               \r
-                               get{\r
-                                       if ((m_position<m_collection.Count)||(m_position<0))\r
-                                               return m_collection.BaseGetKey(m_position);\r
-                                       else \r
-                                               throw new InvalidOperationException();\r
-                               }\r
-                               \r
-                       }\r
-                       public bool MoveNext()\r
-                       {\r
-                               return ((++m_position)<m_collection.Count)?true:false;\r
-                       }\r
-                       public void Reset()\r
-                       {\r
-                               m_position = -1;\r
-                       }\r
-               }\r
-               \r
-               /// <summary>\r
-               /// SDK: Represents a collection of the String keys of a collection.\r
+               private KeysCollection keyscoll;
+               private IEqualityComparer equality_comparer;
+
+               internal IEqualityComparer EqualityComparer {
+                       get { return equality_comparer; }
+               }
+
+               internal IComparer Comparer {
+                       get {return m_comparer;}
+               }
+
+               internal IHashCodeProvider HashCodeProvider {
+                       get {return m_hashprovider;}
+               }
+
+               internal class _Item
+               {
+                       public string key;
+                       public object value;
+                       public _Item(string key, object value)
+                       {
+                               this.key = key;
+                               this.value = value;
+                       }
+               }               
+               /// <summary>
+               /// Implements IEnumerable interface for KeysCollection
                /// </summary>
-               [Serializable]\r
-               public class KeysCollection : ICollection, IEnumerable\r
-               {\r
-                       private NameObjectCollectionBase m_collection;\r
-\r
-                       internal/*protected?*/ KeysCollection(NameObjectCollectionBase collection)\r
-                       {\r
-                               this.m_collection = collection;\r
-                       }\r
-                       public virtual string Get( int index )\r
-                       {\r
-                               return m_collection.BaseGetKey(index);\r
-                               //throw new Exception("Not implemented yet");\r
-                       }\r
-                       \r
-                       // ICollection methods -----------------------------------\r
-                       void ICollection.CopyTo(Array arr, int index)\r
-                       {\r
-                               if (arr==null)\r
-                                       throw new ArgumentNullException("array can't be null");\r
-                               IEnumerator en = this.GetEnumerator();\r
-                               int i = index;\r
-                               while (en.MoveNext())\r
-                               {\r
-                                       arr.SetValue(en.Current,i);\r
-                                       i++;\r
-                               }                       \r
-                       }\r
-\r
-                       bool ICollection.IsSynchronized\r
-                       {\r
-                               get{\r
-                                       return false;\r
-                               }\r
-                       }\r
-                       object ICollection.SyncRoot\r
-                       {\r
-                               get{\r
-                                       return m_collection;\r
-                               }\r
-                       }\r
-                       /// <summary>\r
-                       /// Gets the number of keys in the NameObjectCollectionBase.KeysCollection\r
-                       /// </summary>\r
-                       public int Count \r
-                       {\r
-                               get{\r
-                                       return m_collection.Count;\r
-                                       //throw new Exception("Not implemented yet");\r
-                               }\r
-                       }\r
-\r
-                       public string this [int index] {\r
-                               get { return Get (index); }\r
-                       }\r
-\r
-                       // IEnumerable methods --------------------------------\r
-                       /// <summary>\r
-                       /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.KeysCollection.\r
-                       /// </summary>\r
-                       /// <returns></returns>\r
-                       public IEnumerator GetEnumerator()\r
-                       {\r
-                               return new _KeysEnumerator(m_collection);\r
-//                             throw new Exception("Not implemented yet");\r
-                       }\r
-               }\r
-\r
-\r
-\r
-               //--------------- Protected Instance Constructors --------------\r
-               \r
-               /// <summary>\r
-               /// SDK: Initializes a new instance of the NameObjectCollectionBase class that is empty.\r
-               /// </summary>\r
-               [MonoTODO]\r
-               protected NameObjectCollectionBase():base()\r
-               {\r
-                       m_readonly = false;\r
-                       \r
-                       m_hashprovider = CaseInsensitiveHashCodeProvider.Default;\r
-                       m_comparer = CaseInsensitiveComparer.Default;\r
-                       m_defCapacity = 0;\r
-                       Init();\r
-                       /*m_ItemsContainer = new Hashtable(m_hashprovider,m_comparer);\r
-                       m_ItemsArray = new ArrayList();\r
-                       m_NullKeyItem = null;*/\r
-                       //TODO: consider common Reset() method\r
-               }\r
-               \r
-               protected NameObjectCollectionBase( int capacity )\r
-               {\r
-                       m_readonly = false;\r
-                       \r
-                       m_hashprovider = CaseInsensitiveHashCodeProvider.Default;\r
-                       m_comparer = CaseInsensitiveComparer.Default;\r
-                       m_defCapacity = capacity;\r
-                       Init();\r
-                       /*m_ItemsContainer = new Hashtable(m_defCapacity, m_hashprovider,m_comparer);\r
-                       m_ItemsArray = new ArrayList();\r
-                       m_NullKeyItem = null;                   */\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
-               protected NameObjectCollectionBase( IHashCodeProvider hashProvider, IComparer comparer )\r
-               {\r
-                       m_readonly = false;\r
-                       \r
-                       m_hashprovider = hashProvider;\r
-                       m_comparer = comparer;\r
-                       m_defCapacity = 0;\r
-                       Init();\r
-                       /*m_ItemsContainer = new Hashtable(m_hashprovider,m_comparer);\r
-                       m_ItemsArray = new ArrayList();\r
-                       m_NullKeyItem = null;                   */\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
+               [Serializable]
+               internal class _KeysEnumerator : IEnumerator
+               {
+                       private NameObjectCollectionBase m_collection;
+                       private int m_position;
+
+                       internal _KeysEnumerator(NameObjectCollectionBase collection)
+                       {
+                               m_collection = collection;
+                               Reset();
+                       }
+                       public object Current 
+                       {
+                               
+                               get{
+                                       if ((m_position<m_collection.Count)||(m_position<0))
+                                               return m_collection.BaseGetKey(m_position);
+                                       else 
+                                               throw new InvalidOperationException();
+                               }
+                               
+                       }
+                       public bool MoveNext()
+                       {
+                               return ((++m_position) < m_collection.Count);
+                       }
+                       public void Reset()
+                       {
+                               m_position = -1;
+                       }
+               }
+               
+               /// <summary>
+               /// SDK: Represents a collection of the String keys of a collection.
+               /// </summary>
+               [Serializable]
+               public class KeysCollection : ICollection, IEnumerable
+               {
+                       private NameObjectCollectionBase m_collection;
+
+                       internal KeysCollection (NameObjectCollectionBase collection)
+                       {
+                               this.m_collection = collection;
+                       }
+
+                       public virtual string Get( int index )
+                       {
+                               return m_collection.BaseGetKey(index);
+                       }
+                       
+                       // ICollection methods -----------------------------------
+                       void ICollection.CopyTo (Array array, int arrayIndex)
+                       {
+                               ArrayList items = m_collection.m_ItemsArray;
+                               if (null == array)
+                                       throw new ArgumentNullException ("array");
+
+                               if (arrayIndex < 0)
+                                       throw new ArgumentOutOfRangeException ("arrayIndex");
+
+                               if ((array.Length > 0) && (arrayIndex >= array.Length))
+                                       throw new ArgumentException ("arrayIndex is equal to or greater than array.Length");
+
+                               if (arrayIndex + items.Count > array.Length)
+                                       throw new ArgumentException ("Not enough room from arrayIndex to end of array for this KeysCollection");
+
+                               if (array != null && array.Rank > 1)
+                                       throw new ArgumentException ("array is multidimensional");
+                               
+                               object[] objArray = (object[])array;
+                               for (int i = 0; i < items.Count; i++, arrayIndex++)
+                                       objArray [arrayIndex] = ((_Item)items [i]).key;
+                       }
+
+                       bool ICollection.IsSynchronized
+                       {
+                               get{
+                                       return false;
+                               }
+                       }
+                       object ICollection.SyncRoot
+                       {
+                               get{
+                                       return m_collection;
+                               }
+                       }
+                       /// <summary>
+                       /// Gets the number of keys in the NameObjectCollectionBase.KeysCollection
+                       /// </summary>
+                       public int Count 
+                       {
+                               get{
+                                       return m_collection.Count;
+                               }
+                       }
+
+                       public string this [int index] {
+                               get { return Get (index); }
+                       }
+
+                       // IEnumerable methods --------------------------------
+                       /// <summary>
+                       /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.KeysCollection.
+                       /// </summary>
+                       /// <returns></returns>
+                       public IEnumerator GetEnumerator()
+                       {
+                               return new _KeysEnumerator(m_collection);
+                       }
+               }
+
+               //--------------- Protected Instance Constructors --------------
+               
+               /// <summary>
+               /// SDK: Initializes a new instance of the NameObjectCollectionBase class that is empty.
+               /// </summary>
+               protected NameObjectCollectionBase ()
+               {
+                       m_readonly = false;
+                       m_hashprovider = CaseInsensitiveHashCodeProvider.DefaultInvariant;
+                       m_comparer = CaseInsensitiveComparer.DefaultInvariant;
+                       m_defCapacity = 0;
+                       Init();
+               }
+               
+               protected NameObjectCollectionBase( int capacity )
+               {
+                       m_readonly = false;
+                       m_hashprovider = CaseInsensitiveHashCodeProvider.DefaultInvariant;
+                       m_comparer = CaseInsensitiveComparer.DefaultInvariant;
+                       m_defCapacity = capacity;
+                       Init();
+               }               
+
+               internal NameObjectCollectionBase (IEqualityComparer equalityComparer, IComparer comparer, IHashCodeProvider hcp)
+               {
+                       equality_comparer = equalityComparer;
+                       m_comparer = comparer;
+                       m_hashprovider = hcp;
+                       m_readonly = false;
+                       m_defCapacity = 0;
+                       Init ();
+               }
+
+               protected NameObjectCollectionBase (IEqualityComparer equalityComparer) : this( (equalityComparer == null ? StringComparer.InvariantCultureIgnoreCase : equalityComparer), null, null)
+               {                       
+               }               
+
+               [Obsolete ("Use NameObjectCollectionBase(IEqualityComparer)")]
+               protected NameObjectCollectionBase( IHashCodeProvider hashProvider, IComparer comparer )
+               {                       
+                       m_comparer = comparer;
+                       m_hashprovider = hashProvider;
+                       m_readonly = false;
+                       m_defCapacity = 0;
+                       Init ();
+               }
 
                protected NameObjectCollectionBase (SerializationInfo info, StreamingContext context)
                {
                        infoCopy = info;
                }
 
-               protected NameObjectCollectionBase( int capacity, IHashCodeProvider hashProvider, IComparer comparer )\r
-               {\r
-                       m_readonly = false;\r
-                       \r
-                       m_hashprovider = hashProvider;\r
-                       m_comparer = comparer;\r
-                       m_defCapacity = capacity;\r
-                       Init();\r
-                       /*m_ItemsContainer = new Hashtable(m_defCapacity,m_hashprovider,m_comparer);\r
-                       m_ItemsArray = new ArrayList();\r
-                       m_NullKeyItem = null;   */\r
-\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
-               \r
-               private void Init(){\r
-                       m_ItemsContainer = new Hashtable(m_defCapacity,m_hashprovider,m_comparer);\r
-                       m_ItemsArray = new ArrayList();\r
-                       m_NullKeyItem = null;   \r
-               }\r
-               //--------------- Public Instance Properties -------------------\r
-               public virtual NameObjectCollectionBase.KeysCollection Keys \r
-               {\r
-                       get\r
-                       {\r
-                               return new KeysCollection(this);\r
-                               //throw new Exception("Not implemented yet");\r
-                       }\r
-               }\r
-                               \r
-               //--------------- Public Instance Methods ----------------------\r
-               // \r
-               /// <summary>\r
-               /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.\r
-               /// \r
-               /// <remark>This enumerator returns the keys of the collection as strings.</remark>\r
-               /// </summary>\r
-               /// <returns></returns>\r
-               public IEnumerator GetEnumerator()\r
-               {\r
-                       return new _KeysEnumerator(this);\r
-               }\r
-               // GetHashCode\r
+               protected NameObjectCollectionBase (int capacity, IEqualityComparer equalityComparer)
+               {
+                       m_readonly = false;
+                       equality_comparer = (equalityComparer == null ? StringComparer.InvariantCultureIgnoreCase : equalityComparer);
+                       m_defCapacity = capacity;
+                       Init();
+               }
+
+               [Obsolete ("Use NameObjectCollectionBase(int,IEqualityComparer)")]
+               protected NameObjectCollectionBase( int capacity, IHashCodeProvider hashProvider, IComparer comparer )
+               {
+                       m_readonly = false;
+                       
+                       m_hashprovider = hashProvider;
+                       m_comparer = comparer;
+                       m_defCapacity = capacity;
+                       Init();
+               }
+               
+               private void Init ()
+               {
+                       if (m_ItemsContainer != null) {
+                               m_ItemsContainer.Clear ();
+                               m_ItemsContainer = null;
+                       }
+                       
+                       if (m_ItemsArray != null) {
+                               m_ItemsArray.Clear ();
+                               m_ItemsArray = null;
+                       }
+                       if (equality_comparer != null)
+                               m_ItemsContainer = new Hashtable (m_defCapacity, equality_comparer);
+                       else
+                               m_ItemsContainer = new Hashtable (m_defCapacity, m_hashprovider, m_comparer);
+                       m_ItemsArray = new ArrayList();
+                       m_NullKeyItem = null;   
+               }
+
+               //--------------- Public Instance Properties -------------------
+
+               public virtual NameObjectCollectionBase.KeysCollection Keys {
+                       get {
+                               if (keyscoll == null)
+                                       keyscoll = new KeysCollection (this);
+                               return keyscoll;
+                       }
+               }
+                               
+               //--------------- Public Instance Methods ----------------------
+               // 
+               /// <summary>
+               /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.
+               /// 
+               /// <remark>This enumerator returns the keys of the collection as strings.</remark>
+               /// </summary>
+               /// <returns></returns>
+               public virtual IEnumerator GetEnumerator()
+               {
+                       return new _KeysEnumerator(this);
+               }
 
                // ISerializable
                public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
@@ -266,60 +316,70 @@ namespace System.Collections.Specialized
                                i++;
                        }
 
-                       info.AddValue ("m_hashprovider", m_hashprovider);
-                       info.AddValue ("m_comparer", m_comparer);
-                       info.AddValue ("m_readonly", m_readonly);
-                       info.AddValue ("keys", keys);
-                       info.AddValue ("values", values);
-               }
-
-               // ICollection\r
-               public virtual int Count \r
-               {\r
-                       get{\r
-                               return m_ItemsArray.Count;\r
-                               //throw new Exception("Not implemented yet");\r
-                       }\r
-               }\r
-               bool ICollection.IsSynchronized\r
-               {\r
-                       get { return false; }\r
-               }\r
-               object ICollection.SyncRoot\r
-               {\r
-                       get { return this; }\r
-               }\r
-\r
-               void ICollection.CopyTo (Array array, int index)\r
-               {\r
-                       throw new NotImplementedException ();\r
-               }\r
+                       if (equality_comparer != null) {
+                               info.AddValue ("KeyComparer", equality_comparer, typeof (IEqualityComparer));
+                               info.AddValue ("Version", 4, typeof (int));
+                       } else {
+                               info.AddValue ("HashProvider", m_hashprovider, typeof (IHashCodeProvider));
+                               info.AddValue ("Comparer", m_comparer, typeof (IComparer));
+                               info.AddValue ("Version", 2, typeof (int));
+                       }
+                       info.AddValue("ReadOnly", m_readonly);
+                       info.AddValue("Count", count);
+                       info.AddValue("Keys", keys, typeof(string[]));
+                       info.AddValue("Values", values, typeof(object[]));
+               }
 
+               // ICollection
+               public virtual int Count 
+               {
+                       get{
+                               return m_ItemsArray.Count;
+                       }
+               }
+
+               bool ICollection.IsSynchronized
+               {
+                       get { return false; }
+               }
+
+               object ICollection.SyncRoot
+               {
+                       get { return this; }
+               }
+
+               void ICollection.CopyTo (Array array, int index)
+               {
+                       ((ICollection)Keys).CopyTo (array, index);
+               }
 
                // IDeserializationCallback
                public virtual void OnDeserialization (object sender)
                {
                        SerializationInfo info = infoCopy;
+                       
+                       // If a subclass overrides the serialization constructor
+                       // and inplements its own serialization process, infoCopy will
+                       // be null and we can ignore this callback.
                        if (info == null)
-                               throw new SerializationException ("The object is not a SerializationInfo");
+                               return;
 
                        infoCopy = null;
-                       m_hashprovider = (IHashCodeProvider) info.GetValue ("m_hashprovider",
+                       m_hashprovider = (IHashCodeProvider) info.GetValue ("HashProvider",
                                                                            typeof (IHashCodeProvider));
-
-                       if (m_hashprovider == null)
-                               throw new SerializationException ("The hash provider is null");
-
-                       m_comparer = (IComparer) info.GetValue ("m_comparer", typeof (IComparer));
-                       if (m_comparer == null)
-                               throw new SerializationException ("The comparer is null");
-
-                       m_readonly = info.GetBoolean ("m_readonly");
-                       string [] keys = (string []) info.GetValue ("keys", typeof (string []));
+                       if (m_hashprovider == null) {
+                               equality_comparer = (IEqualityComparer) info.GetValue ("KeyComparer", typeof (IEqualityComparer));
+                       } else {
+                               m_comparer = (IComparer) info.GetValue ("Comparer", typeof (IComparer));
+                               if (m_comparer == null)
+                                       throw new SerializationException ("The comparer is null");
+                       }
+                       m_readonly = info.GetBoolean ("ReadOnly");
+                       string [] keys = (string []) info.GetValue ("Keys", typeof (string []));
                        if (keys == null)
                                throw new SerializationException ("keys is null");
 
-                       object [] values = (object []) info.GetValue ("values", typeof (object []));
+                       object [] values = (object []) info.GetValue ("Values", typeof (object []));
                        if (values == null)
                                throw new SerializationException ("values is null");
 
@@ -328,232 +388,233 @@ namespace System.Collections.Specialized
                        for (int i = 0; i < count; i++)
                                BaseAdd (keys [i], values [i]);
                }
-               //--------------- Protected Instance Properties ----------------\r
-               /// <summary>\r
-               /// SDK: Gets or sets a value indicating whether the NameObjectCollectionBase instance is read-only.\r
-               /// </summary>\r
-               protected bool IsReadOnly \r
-               {\r
-                       get{\r
-                               return m_readonly;\r
-                       }\r
-                       set{\r
-                               m_readonly=value;\r
-                       }\r
-               }\r
-               \r
-               //--------------- Protected Instance Methods -------------------\r
-               /// <summary>\r
-               /// Adds an Item with the specified key and value into the <see cref="NameObjectCollectionBase"/>NameObjectCollectionBase instance.\r
-               /// </summary>\r
-               /// <param name="name"></param>\r
-               /// <param name="value"></param>\r
-               protected void BaseAdd( string name, object value )\r
-               {\r
-                       if (this.IsReadOnly)\r
-                               throw new NotSupportedException("Collection is read-only");\r
-                       \r
-                       _Item newitem=new _Item(name, value);\r
-\r
-                       if (name==null){\r
-                               //todo: consider nullkey entry\r
-                               if (m_NullKeyItem==null)\r
-                                       m_NullKeyItem = newitem;\r
-                       }\r
-                       else\r
-                               if (m_ItemsContainer[name]==null){\r
-                                       m_ItemsContainer.Add(name,newitem);\r
-                               }\r
-                       m_ItemsArray.Add(newitem);\r
-               }
-
-               protected void BaseClear()\r
-               {\r
-                       if (this.IsReadOnly)\r
-                               throw new NotSupportedException("Collection is read-only");\r
-                       Init();\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
-               /// <summary>\r
-               /// SDK: Gets the value of the entry at the specified index of the NameObjectCollectionBase instance.\r
-               /// </summary>\r
-               /// <param name="index"></param>\r
-               /// <returns></returns>\r
-               protected object BaseGet( int index )\r
-               {\r
-                       return ((_Item)m_ItemsArray[index]).value;\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
-               /// <summary>\r
-               /// SDK: Gets the value of the first entry with the specified key from the NameObjectCollectionBase instance.\r
-               /// </summary>\r
-               /// <remark>CAUTION: The BaseGet method does not distinguish between a null reference which is returned because the specified key is not found and a null reference which is returned because the value associated with the key is a null reference.</remark>\r
-               /// <param name="name"></param>\r
-               /// <returns></returns>\r
-               protected object BaseGet( string name )\r
-               {\r
-                       _Item item = FindFirstMatchedItem(name);\r
-                       /// CAUTION: The BaseGet method does not distinguish between a null reference which is returned because the specified key is not found and a null reference which is returned because the value associated with the key is a null reference.\r
-                       if (item==null)\r
-                               return null;\r
-                       else\r
-                               return item.value;\r
-               }\r
-\r
-               /// <summary>\r
-               /// SDK:Returns a String array that contains all the keys in the NameObjectCollectionBase instance.\r
-               /// </summary>\r
-               /// <returns>A String array that contains all the keys in the NameObjectCollectionBase instance.</returns>\r
-               protected string[] BaseGetAllKeys()\r
-               {\r
-                       int cnt = m_ItemsArray.Count;\r
-                       string[] allKeys = new string[cnt];\r
-                       for(int i=0; i<cnt; i++)\r
-                               allKeys[i] = BaseGetKey(i);//((_Item)m_ItemsArray[i]).key;\r
-                       \r
-                       return allKeys;\r
-               }\r
-\r
-               /// <summary>\r
-               /// SDK: Returns an Object array that contains all the values in the NameObjectCollectionBase instance.\r
-               /// </summary>\r
-               /// <returns>An Object array that contains all the values in the NameObjectCollectionBase instance.</returns>\r
-               protected object[] BaseGetAllValues()\r
-               {\r
-                       int cnt = m_ItemsArray.Count;\r
-                       object[] allValues = new object[cnt];\r
-                       for(int i=0; i<cnt; i++)\r
-                               allValues[i] = BaseGet(i);\r
-                       \r
-                       return allValues;\r
-               }
-\r
-               protected object[] BaseGetAllValues( Type type )\r
-               {\r
-                       if (type == null)\r
-                               throw new ArgumentNullException("'type' argument can't be null");\r
-                       int cnt = m_ItemsArray.Count;\r
-                       object[] allValues = (object[]) Array.CreateInstance (type, cnt);\r
-                       for(int i=0; i<cnt; i++)\r
-                               allValues[i] = BaseGet(i);\r
-                       \r
-                       return allValues;\r
-               }\r
-               \r
-               protected string BaseGetKey( int index )\r
-               {\r
-                       return ((_Item)m_ItemsArray[index]).key;\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
-               /// <summary>\r
-               /// Gets a value indicating whether the NameObjectCollectionBase instance contains entries whose keys are not a null reference \r
-               /// </summary>\r
-               /// <returns>true if the NameObjectCollectionBase instance contains entries whose keys are not a null reference otherwise, false.</returns>\r
-               protected bool BaseHasKeys()\r
-               {\r
-                       return (m_ItemsContainer.Count>0);\r
-//                     throw new Exception("Not implemented yet");\r
-               }\r
-
-               protected void BaseRemove( string name )\r
-               {\r
-                       int cnt = 0;\r
-                       String key;\r
-                       if (this.IsReadOnly)\r
-                               throw new NotSupportedException("Collection is read-only");\r
-                       if (name!=null)\r
-                       {\r
-                               m_ItemsContainer.Remove(name);\r
-                       }\r
-                       else {\r
-                               m_NullKeyItem = null;\r
-                       }\r
-                       \r
-                       cnt = m_ItemsArray.Count;\r
-                       for (int i=0 ; i< cnt; ){\r
-                               key=BaseGetKey(i);\r
-                               if (m_comparer.Compare (key, name) == 0) {\r
-                                       m_ItemsArray.RemoveAt(i);\r
-                                       cnt--;\r
-                               }\r
-                               else \r
-                                       i++;\r
-                               \r
-                       }\r
-               }
-\r
-               /// <summary>\r
-               /// \r
-               /// </summary>\r
-               /// <param name="index"></param>\r
-               /// <LAME>This function implemented the way Microsoft implemented it - \r
-               /// item is removed from hashtable and array without considering the case when there are two items with the same key but different values in array.\r
-               /// E.g. if\r
-               /// hashtable is [("Key1","value1")] and array contains [("Key1","value1")("Key1","value2")] then\r
-               /// after RemoveAt(1) the collection will be in following state:\r
-               /// hashtable:[] \r
-               /// array: [("Key1","value1")] \r
-               /// It's ok only then the key is uniquely assosiated with the value\r
-               /// To fix it a comparsion of objects stored under the same key in the hashtable and in the arraylist should be added \r
-               /// </LAME>>\r
-               [MonoTODO]\r
-               protected void BaseRemoveAt( int index )\r
-               {\r
-                       if (this.IsReadOnly)\r
-                               throw new NotSupportedException("Collection is read-only");\r
-                       string key = BaseGetKey(index);\r
-                       if (key!=null){\r
-                               // TODO: see LAME description above\r
-                               m_ItemsContainer.Remove(key);\r
-                       }\r
-                       else\r
-                               m_NullKeyItem = null;\r
-                       m_ItemsArray.RemoveAt(index);\r
-//                     throw new Exception("Not implemented yet");\r
-               }\r
-               /// <summary>\r
-               /// SDK: Sets the value of the entry at the specified index of the NameObjectCollectionBase instance.\r
-               /// </summary>\r
-               /// <param name="index"></param>\r
-               /// <param name="value"></param>\r
-               protected void BaseSet( int index, object value )\r
-               {\r
-                       if (this.IsReadOnly)\r
-                               throw new NotSupportedException("Collection is read-only");\r
-                       _Item item = (_Item)m_ItemsArray[index];\r
-                       item.value = value;\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
-               /// <summary>\r
-               /// Sets the value of the first entry with the specified key in the NameObjectCollectionBase instance, if found; otherwise, adds an entry with the specified key and value into the NameObjectCollectionBase instance.\r
-               /// </summary>\r
-               /// <param name="name">The String key of the entry to set. The key can be a null reference </param>\r
-               /// <param name="value">The Object that represents the new value of the entry to set. The value can be a null reference</param>\r
-               protected void BaseSet( string name, object value )\r
-               {\r
-                       if (this.IsReadOnly)\r
-                               throw new NotSupportedException("Collection is read-only");\r
-                       _Item item = FindFirstMatchedItem(name);\r
-                       if (item!=null)\r
-                               item.value=value;\r
-                       else \r
-                               BaseAdd(name, value);\r
-\r
-                       //throw new Exception("Not implemented yet");\r
-               }\r
-               [MonoTODO]\r
-               private _Item FindFirstMatchedItem(string name)\r
-               {\r
-                       if (name!=null)\r
-                               return (_Item)m_ItemsContainer[name];\r
-                       else {\r
-                               //TODO: consider null key case\r
-                               return m_NullKeyItem;\r
-                               //throw new Exception("Not implemented yet");\r
-                       }\r
-\r
-               }\r
-               //~Object();\r
-               \r
-       }\r
-}\r
+
+               //--------------- Protected Instance Properties ----------------
+               /// <summary>
+               /// SDK: Gets or sets a value indicating whether the NameObjectCollectionBase instance is read-only.
+               /// </summary>
+               protected bool IsReadOnly 
+               {
+                       get{
+                               return m_readonly;
+                       }
+                       set{
+                               m_readonly=value;
+                       }
+               }
+               
+               //--------------- Protected Instance Methods -------------------
+               /// <summary>
+               /// Adds an Item with the specified key and value into the <see cref="NameObjectCollectionBase"/>NameObjectCollectionBase instance.
+               /// </summary>
+               /// <param name="name"></param>
+               /// <param name="value"></param>
+               protected void BaseAdd( string name, object value )
+               {
+                       if (this.IsReadOnly)
+                               throw new NotSupportedException("Collection is read-only");
+                       
+                       _Item newitem=new _Item(name, value);
+
+                       if (name==null){
+                               //todo: consider nullkey entry
+                               if (m_NullKeyItem==null)
+                                       m_NullKeyItem = newitem;
+                       }
+                       else
+                               if (m_ItemsContainer[name]==null){
+                                       m_ItemsContainer.Add(name,newitem);
+                               }
+                       m_ItemsArray.Add(newitem);
+               }
+
+               protected void BaseClear()
+               {
+                       if (this.IsReadOnly)
+                               throw new NotSupportedException("Collection is read-only");
+                       Init();
+               }
+
+               /// <summary>
+               /// SDK: Gets the value of the entry at the specified index of the NameObjectCollectionBase instance.
+               /// </summary>
+               /// <param name="index"></param>
+               /// <returns></returns>
+               protected object BaseGet( int index )
+               {
+                       return ((_Item)m_ItemsArray[index]).value;
+               }
+
+               /// <summary>
+               /// SDK: Gets the value of the first entry with the specified key from the NameObjectCollectionBase instance.
+               /// </summary>
+               /// <remark>CAUTION: The BaseGet method does not distinguish between a null reference which is returned because the specified key is not found and a null reference which is returned because the value associated with the key is a null reference.</remark>
+               /// <param name="name"></param>
+               /// <returns></returns>
+               protected object BaseGet( string name )
+               {
+                       _Item item = FindFirstMatchedItem(name);
+                       /// CAUTION: The BaseGet method does not distinguish between a null reference which is returned because the specified key is not found and a null reference which is returned because the value associated with the key is a null reference.
+                       if (item==null)
+                               return null;
+                       else
+                               return item.value;
+               }
+
+               /// <summary>
+               /// SDK:Returns a String array that contains all the keys in the NameObjectCollectionBase instance.
+               /// </summary>
+               /// <returns>A String array that contains all the keys in the NameObjectCollectionBase instance.</returns>
+               protected string[] BaseGetAllKeys()
+               {
+                       int cnt = m_ItemsArray.Count;
+                       string[] allKeys = new string[cnt];
+                       for(int i=0; i<cnt; i++)
+                               allKeys[i] = BaseGetKey(i);//((_Item)m_ItemsArray[i]).key;
+                       
+                       return allKeys;
+               }
+
+               /// <summary>
+               /// SDK: Returns an Object array that contains all the values in the NameObjectCollectionBase instance.
+               /// </summary>
+               /// <returns>An Object array that contains all the values in the NameObjectCollectionBase instance.</returns>
+               protected object[] BaseGetAllValues()
+               {
+                       int cnt = m_ItemsArray.Count;
+                       object[] allValues = new object[cnt];
+                       for(int i=0; i<cnt; i++)
+                               allValues[i] = BaseGet(i);
+                       
+                       return allValues;
+               }
+
+               protected object[] BaseGetAllValues( Type type )
+               {
+                       if (type == null)
+                               throw new ArgumentNullException("'type' argument can't be null");
+                       int cnt = m_ItemsArray.Count;
+                       object[] allValues = (object[]) Array.CreateInstance (type, cnt);
+                       for(int i=0; i<cnt; i++)
+                               allValues[i] = BaseGet(i);
+                       
+                       return allValues;
+               }
+               
+               protected string BaseGetKey( int index )
+               {
+                       return ((_Item)m_ItemsArray[index]).key;
+               }
+
+               /// <summary>
+               /// Gets a value indicating whether the NameObjectCollectionBase instance contains entries whose keys are not a null reference 
+               /// </summary>
+               /// <returns>true if the NameObjectCollectionBase instance contains entries whose keys are not a null reference otherwise, false.</returns>
+               protected bool BaseHasKeys()
+               {
+                       return (m_ItemsContainer.Count>0);
+               }
+
+               protected void BaseRemove( string name )
+               {
+                       int cnt = 0;
+                       String key;
+                       if (this.IsReadOnly)
+                               throw new NotSupportedException("Collection is read-only");
+                       if (name!=null)
+                       {
+                               m_ItemsContainer.Remove(name);
+                       }
+                       else {
+                               m_NullKeyItem = null;
+                       }
+                       
+                       cnt = m_ItemsArray.Count;
+                       for (int i=0 ; i< cnt; ){
+                               key=BaseGetKey(i);
+                               if (Equals (key, name)) {
+                                       m_ItemsArray.RemoveAt(i);
+                                       cnt--;
+                               }
+                               else 
+                                       i++;
+                       }
+               }
+
+               /// <summary>
+               /// 
+               /// </summary>
+               /// <param name="index"></param>
+               /// <LAME>This function implemented the way Microsoft implemented it - 
+               /// item is removed from hashtable and array without considering the case when there are two items with the same key but different values in array.
+               /// E.g. if
+               /// hashtable is [("Key1","value1")] and array contains [("Key1","value1")("Key1","value2")] then
+               /// after RemoveAt(1) the collection will be in following state:
+               /// hashtable:[] 
+               /// array: [("Key1","value1")] 
+               /// It's ok only then the key is uniquely assosiated with the value
+               /// To fix it a comparsion of objects stored under the same key in the hashtable and in the arraylist should be added 
+               /// </LAME>>
+               protected void BaseRemoveAt( int index )
+               {
+                       if (this.IsReadOnly)
+                               throw new NotSupportedException("Collection is read-only");
+                       string key = BaseGetKey(index);
+                       if (key!=null){
+                               // TODO: see LAME description above
+                               m_ItemsContainer.Remove(key);
+                       }
+                       else
+                               m_NullKeyItem = null;
+                       m_ItemsArray.RemoveAt(index);
+               }
+
+               /// <summary>
+               /// SDK: Sets the value of the entry at the specified index of the NameObjectCollectionBase instance.
+               /// </summary>
+               /// <param name="index"></param>
+               /// <param name="value"></param>
+               protected void BaseSet( int index, object value )
+               {
+                       if (this.IsReadOnly)
+                               throw new NotSupportedException("Collection is read-only");
+                       _Item item = (_Item)m_ItemsArray[index];
+                       item.value = value;
+               }
+
+               /// <summary>
+               /// Sets the value of the first entry with the specified key in the NameObjectCollectionBase instance, if found; otherwise, adds an entry with the specified key and value into the NameObjectCollectionBase instance.
+               /// </summary>
+               /// <param name="name">The String key of the entry to set. The key can be a null reference </param>
+               /// <param name="value">The Object that represents the new value of the entry to set. The value can be a null reference</param>
+               protected void BaseSet( string name, object value )
+               {
+                       if (this.IsReadOnly)
+                               throw new NotSupportedException("Collection is read-only");
+                       _Item item = FindFirstMatchedItem(name);
+                       if (item!=null)
+                               item.value=value;
+                       else 
+                               BaseAdd(name, value);
+               }
+
+               [MonoTODO]
+               private _Item FindFirstMatchedItem(string name)
+               {
+                       if (name!=null)
+                               return (_Item)m_ItemsContainer[name];
+                       else {
+                               //TODO: consider null key case
+                               return m_NullKeyItem;
+                       }
+               }
+
+               internal bool Equals (string s1, string s2)
+               {
+                       if (m_comparer != null)
+                               return (m_comparer.Compare (s1, s2) == 0);
+                       else
+                               return equality_comparer.Equals (s1, s2);
+               }
+       }
+}