| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- //
- // System.Collections.Specialized.NameObjectCollectionBase.cs
- //
- // Author:
- // Gleb Novodran
- // Andreas Nahr ([email protected])
- //
- // (C) Ximian, Inc. http://www.ximian.com
- // 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;
- private KeysCollection keyscoll;
- #if NET_2_0
- private IEqualityComparer equality_comparer;
- internal IEqualityComparer EqualityComparer {
- get { return equality_comparer; }
- }
- #endif
- 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]
- 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)?true:false;
- }
- 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 arr, int index)
- {
- if (arr==null)
- throw new ArgumentNullException("array can't be null");
- IEnumerator en = this.GetEnumerator();
- int i = index;
- while (en.MoveNext())
- {
- arr.SetValue(en.Current,i);
- i++;
- }
- }
- 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;
- #if NET_1_0
- m_hashprovider = CaseInsensitiveHashCodeProvider.Default;
- m_comparer = CaseInsensitiveComparer.Default;
- #else
- m_hashprovider = CaseInsensitiveHashCodeProvider.DefaultInvariant;
- m_comparer = CaseInsensitiveComparer.DefaultInvariant;
- #endif
- m_defCapacity = 0;
- Init();
- }
-
- protected NameObjectCollectionBase( int capacity )
- {
- m_readonly = false;
- #if NET_1_0
- m_hashprovider = CaseInsensitiveHashCodeProvider.Default;
- m_comparer = CaseInsensitiveComparer.Default;
- #else
- m_hashprovider = CaseInsensitiveHashCodeProvider.DefaultInvariant;
- m_comparer = CaseInsensitiveComparer.DefaultInvariant;
- #endif
- m_defCapacity = capacity;
- Init();
- }
- #if NET_2_0
- protected NameObjectCollectionBase (IEqualityComparer equalityComparer)
- {
- m_readonly = false;
- equality_comparer = equalityComparer;
- m_defCapacity = 0;
- Init();
- }
- [Obsolete ("Use NameObjectCollectionBase(IEqualityComparer)")]
- #endif
- protected NameObjectCollectionBase( IHashCodeProvider hashProvider, IComparer comparer )
- {
- m_readonly = false;
-
- m_hashprovider = hashProvider;
- m_comparer = comparer;
- m_defCapacity = 0;
- Init();
- }
- protected NameObjectCollectionBase (SerializationInfo info, StreamingContext context)
- {
- infoCopy = info;
- }
- #if NET_2_0
- protected NameObjectCollectionBase (int capacity, IEqualityComparer equalityComparer)
- {
- m_readonly = false;
- equality_comparer = equalityComparer;
- m_defCapacity = capacity;
- Init();
- }
- [Obsolete ("Use NameObjectCollectionBase(int,IEqualityComparer)")]
- #endif
- 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 NET_2_0
- if (equality_comparer != null)
- m_ItemsContainer = new Hashtable (m_defCapacity, equality_comparer);
- else
- m_ItemsContainer = new Hashtable (m_defCapacity, m_hashprovider, m_comparer);
- #else
- m_ItemsContainer = new Hashtable (m_defCapacity, m_hashprovider, m_comparer);
- #endif
- 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
- #if NET_2_0
- virtual
- #endif
- IEnumerator GetEnumerator()
- {
- return new _KeysEnumerator(this);
- }
- // ISerializable
- public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
- {
- if (info == null)
- throw new ArgumentNullException ("info");
- int count = Count;
- string [] keys = new string [count];
- object [] values = new object [count];
- int i = 0;
- foreach (_Item item in m_ItemsArray) {
- keys [i] = item.key;
- values [i] = item.value;
- i++;
- }
- #if NET_2_0
- 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));
- }
- #else
- info.AddValue ("HashProvider", m_hashprovider, typeof (IHashCodeProvider));
- info.AddValue ("Comparer", m_comparer, typeof (IComparer));
- #endif
- 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)
- {
- (Keys as ICollection).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)
- return;
- infoCopy = null;
- m_hashprovider = (IHashCodeProvider) info.GetValue ("HashProvider",
- typeof (IHashCodeProvider));
- #if NET_2_0
- 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");
- }
- #else
- if (m_hashprovider == null)
- throw new SerializationException ("The hash provider is null");
- m_comparer = (IComparer) info.GetValue ("Comparer", typeof (IComparer));
- if (m_comparer == null)
- throw new SerializationException ("The comparer is null");
- #endif
- 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 []));
- if (values == null)
- throw new SerializationException ("values is null");
- Init ();
- int count = keys.Length;
- for (int i = 0; i < count; i++)
- BaseAdd (keys [i], values [i]);
- }
- //--------------- 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>>
- [MonoTODO]
- 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 NET_2_0
- if (m_comparer != null)
- return (m_comparer.Compare (s1, s2) == 0);
- else
- return equality_comparer.Equals (s1, s2);
- #else
- return (m_comparer.Compare (s1, s2) == 0);
- #endif
- }
- }
- }
|