2 using System
.Collections
;
3 using System
.Runtime
.Serialization
;
6 namespace System
.Collections
.Specialized
9 public abstract class NameObjectCollectionBase
: ICollection
, IEnumerable
, ISerializable
, IDeserializationCallback
11 private Hashtable m_ItemsContainer
;
13 /// Extends Hashtable based Items container to support storing null-key pairs
15 private _Item m_NullKeyItem
;
16 private ArrayList m_ItemsArray
;
17 private IHashCodeProvider m_hashprovider
;
18 private IComparer m_comparer
;
19 private int m_defCapacity
;
20 private bool m_readonly
;
21 SerializationInfo infoCopy
;
22 private KeysCollection keyscoll
;
24 private IEqualityComparer equality_comparer
;
26 internal IEqualityComparer EqualityComparer
{
27 get { return equality_comparer; }
30 internal IComparer Comparer
32 get { return m_comparer; }
35 internal IHashCodeProvider HashCodeProvider
37 get { return m_hashprovider; }
44 public _Item(string key
, object value)
51 /// Implements IEnumerable interface for KeysCollection
54 internal class _KeysEnumerator
: IEnumerator
56 private NameObjectCollectionBase m_collection
;
57 private int m_position
;
59 internal _KeysEnumerator(NameObjectCollectionBase collection
)
61 m_collection
= collection
;
69 if ((m_position
< m_collection
.Count
) || (m_position
< 0))
70 return m_collection
.BaseGetKey(m_position
);
72 throw new InvalidOperationException();
76 public bool MoveNext()
78 return ((++m_position
) < m_collection
.Count
);
87 /// SDK: Represents a collection of the String keys of a collection.
90 public class KeysCollection
: ICollection
, IEnumerable
92 private NameObjectCollectionBase m_collection
;
94 internal KeysCollection(NameObjectCollectionBase collection
)
96 this.m_collection
= collection
;
99 public virtual string Get(int index
)
101 return m_collection
.BaseGetKey(index
);
104 // ICollection methods -----------------------------------
105 void ICollection
.CopyTo(Array array
, int arrayIndex
)
107 ArrayList items
= m_collection
.m_ItemsArray
;
110 throw new ArgumentNullException ("array");
113 throw new ArgumentOutOfRangeException ("arrayIndex");
115 if ((array
.Length
> 0) && (arrayIndex
>= array
.Length
))
116 throw new ArgumentException ("arrayIndex is equal to or greater than array.Length");
118 if (arrayIndex
+ items
.Count
> array
.Length
)
119 throw new ArgumentException ("Not enough room from arrayIndex to end of array for this KeysCollection");
122 if (array
!= null && array
.Rank
> 1)
123 throw new ArgumentException("array is multidimensional");
125 object[] objArray
= (object[])array
;
126 for (int i
= 0; i
< items
.Count
; i
++, arrayIndex
++)
127 objArray
[arrayIndex
] = ((_Item
)items
[i
]).key
;
130 bool ICollection
.IsSynchronized
137 object ICollection
.SyncRoot
145 /// Gets the number of keys in the NameObjectCollectionBase.KeysCollection
151 return m_collection
.Count
;
155 public string this[int index
]
157 get { return Get(index); }
160 // IEnumerable methods --------------------------------
162 /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.KeysCollection.
164 /// <returns></returns>
165 public IEnumerator
GetEnumerator()
167 return new _KeysEnumerator(m_collection
);
171 //--------------- Protected Instance Constructors --------------
174 /// SDK: Initializes a new instance of the NameObjectCollectionBase class that is empty.
176 protected NameObjectCollectionBase()
180 m_hashprovider
= CaseInsensitiveHashCodeProvider
.Default
;
181 m_comparer
= CaseInsensitiveComparer
.Default
;
183 m_hashprovider
= CaseInsensitiveHashCodeProvider
.DefaultInvariant
;
184 m_comparer
= CaseInsensitiveComparer
.DefaultInvariant
;
190 protected NameObjectCollectionBase(int capacity
)
194 m_hashprovider
= CaseInsensitiveHashCodeProvider
.Default
;
195 m_comparer
= CaseInsensitiveComparer
.Default
;
197 m_hashprovider
= CaseInsensitiveHashCodeProvider
.DefaultInvariant
;
198 m_comparer
= CaseInsensitiveComparer
.DefaultInvariant
;
200 m_defCapacity
= capacity
;
206 internal NameObjectCollectionBase (IEqualityComparer equalityComparer
, IComparer comparer
, IHashCodeProvider hcp
)
208 equality_comparer
= equalityComparer
;
209 m_comparer
= comparer
;
210 m_hashprovider
= hcp
;
216 protected NameObjectCollectionBase (IEqualityComparer equalityComparer
) : this( (equalityComparer
== null ? StringComparer
.InvariantCultureIgnoreCase
: equalityComparer
), null, null)
220 [Obsolete ("Use NameObjectCollectionBase(IEqualityComparer)")]
222 protected NameObjectCollectionBase(IHashCodeProvider hashProvider
, IComparer comparer
)
224 m_comparer
= comparer
;
225 m_hashprovider
= hashProvider
;
231 protected NameObjectCollectionBase(SerializationInfo info
, StreamingContext context
)
237 protected NameObjectCollectionBase (int capacity
, IEqualityComparer equalityComparer
)
240 equality_comparer
= (equalityComparer
== null ? StringComparer
.InvariantCultureIgnoreCase
: equalityComparer
);
241 m_defCapacity
= capacity
;
245 [Obsolete ("Use NameObjectCollectionBase(int,IEqualityComparer)")]
247 protected NameObjectCollectionBase(int capacity
, IHashCodeProvider hashProvider
, IComparer comparer
)
251 m_hashprovider
= hashProvider
;
252 m_comparer
= comparer
;
253 m_defCapacity
= capacity
;
260 if (equality_comparer
!= null)
261 m_ItemsContainer
= new Hashtable (m_defCapacity
, equality_comparer
);
263 m_ItemsContainer
= new Hashtable (m_defCapacity
, m_hashprovider
, m_comparer
);
265 m_ItemsContainer
= new Hashtable(m_defCapacity
, m_hashprovider
, m_comparer
);
267 m_ItemsArray
= new ArrayList();
268 m_NullKeyItem
= null;
271 //--------------- Public Instance Properties -------------------
273 public virtual NameObjectCollectionBase
.KeysCollection Keys
277 if (keyscoll
== null)
278 keyscoll
= new KeysCollection(this);
283 //--------------- Public Instance Methods ----------------------
286 /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.
288 /// <remark>This enumerator returns the keys of the collection as strings.</remark>
290 /// <returns></returns>
295 IEnumerator
GetEnumerator()
297 return new _KeysEnumerator(this);
301 public virtual void GetObjectData(SerializationInfo info
, StreamingContext context
)
304 throw new ArgumentNullException("info");
307 string[] keys
= new string[count
];
308 object[] values
= new object[count
];
310 foreach (_Item item
in m_ItemsArray
)
313 values
[i
] = item
.value;
318 if (equality_comparer
!= null) {
319 info
.AddValue ("KeyComparer", equality_comparer
, typeof (IEqualityComparer
));
320 info
.AddValue ("Version", 4, typeof (int));
322 info
.AddValue ("HashProvider", m_hashprovider
, typeof (IHashCodeProvider
));
323 info
.AddValue ("Comparer", m_comparer
, typeof (IComparer
));
324 info
.AddValue ("Version", 2, typeof (int));
327 info
.AddValue("HashProvider", m_hashprovider
, typeof(IHashCodeProvider
));
328 info
.AddValue("Comparer", m_comparer
, typeof(IComparer
));
330 info
.AddValue("ReadOnly", m_readonly
);
331 info
.AddValue("Count", count
);
332 info
.AddValue("Keys", keys
, typeof(string[]));
333 info
.AddValue("Values", values
, typeof(object[]));
337 public virtual int Count
341 return m_ItemsArray
.Count
;
345 bool ICollection
.IsSynchronized
347 get { return false; }
350 object ICollection
.SyncRoot
355 void ICollection
.CopyTo(Array array
, int index
)
357 ((ICollection
)Keys
).CopyTo(array
, index
);
360 // IDeserializationCallback
361 public virtual void OnDeserialization(object sender
)
363 SerializationInfo info
= infoCopy
;
365 // If a subclass overrides the serialization constructor
366 // and inplements its own serialization process, infoCopy will
367 // be null and we can ignore this callback.
372 m_hashprovider
= (IHashCodeProvider
)info
.GetValue("HashProvider",
373 typeof(IHashCodeProvider
));
375 if (m_hashprovider
== null) {
376 equality_comparer
= (IEqualityComparer
) info
.GetValue ("KeyComparer", typeof (IEqualityComparer
));
378 m_comparer
= (IComparer
) info
.GetValue ("Comparer", typeof (IComparer
));
379 if (m_comparer
== null)
380 throw new SerializationException ("The comparer is null");
383 if (m_hashprovider
== null)
384 throw new SerializationException("The hash provider is null");
386 m_comparer
= (IComparer
)info
.GetValue("Comparer", typeof(IComparer
));
387 if (m_comparer
== null)
388 throw new SerializationException("The comparer is null");
390 m_readonly
= info
.GetBoolean("ReadOnly");
391 string[] keys
= (string[])info
.GetValue("Keys", typeof(string[]));
393 throw new SerializationException("keys is null");
395 object[] values
= (object[])info
.GetValue("Values", typeof(object[]));
397 throw new SerializationException("values is null");
400 int count
= keys
.Length
;
401 for (int i
= 0; i
< count
; i
++)
402 BaseAdd(keys
[i
], values
[i
]);
405 //--------------- Protected Instance Properties ----------------
407 /// SDK: Gets or sets a value indicating whether the NameObjectCollectionBase instance is read-only.
409 protected bool IsReadOnly
421 //--------------- Protected Instance Methods -------------------
423 /// Adds an Item with the specified key and value into the <see cref="NameObjectCollectionBase"/>NameObjectCollectionBase instance.
425 /// <param name="name"></param>
426 /// <param name="value"></param>
427 protected void BaseAdd(string name
, object value)
430 throw new NotSupportedException("Collection is read-only");
432 _Item newitem
= new _Item(name
, value);
436 //todo: consider nullkey entry
437 if (m_NullKeyItem
== null)
438 m_NullKeyItem
= newitem
;
441 if (m_ItemsContainer
[name
] == null)
443 m_ItemsContainer
.Add(name
, newitem
);
445 m_ItemsArray
.Add(newitem
);
448 protected void BaseClear()
451 throw new NotSupportedException("Collection is read-only");
456 /// SDK: Gets the value of the entry at the specified index of the NameObjectCollectionBase instance.
458 /// <param name="index"></param>
459 /// <returns></returns>
460 protected object BaseGet(int index
)
462 return ((_Item
)m_ItemsArray
[index
]).value;
466 /// SDK: Gets the value of the first entry with the specified key from the NameObjectCollectionBase instance.
468 /// <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>
469 /// <param name="name"></param>
470 /// <returns></returns>
471 protected object BaseGet(string name
)
473 _Item item
= FindFirstMatchedItem(name
);
474 /// 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.
482 /// SDK:Returns a String array that contains all the keys in the NameObjectCollectionBase instance.
484 /// <returns>A String array that contains all the keys in the NameObjectCollectionBase instance.</returns>
485 protected string[] BaseGetAllKeys()
487 int cnt
= m_ItemsArray
.Count
;
488 string[] allKeys
= new string[cnt
];
489 for (int i
= 0; i
< cnt
; i
++)
490 allKeys
[i
] = BaseGetKey(i
);//((_Item)m_ItemsArray[i]).key;
496 /// SDK: Returns an Object array that contains all the values in the NameObjectCollectionBase instance.
498 /// <returns>An Object array that contains all the values in the NameObjectCollectionBase instance.</returns>
499 protected object[] BaseGetAllValues()
501 int cnt
= m_ItemsArray
.Count
;
502 object[] allValues
= new object[cnt
];
503 for (int i
= 0; i
< cnt
; i
++)
504 allValues
[i
] = BaseGet(i
);
509 protected object[] BaseGetAllValues(Type type
)
512 throw new ArgumentNullException("'type' argument can't be null");
513 int cnt
= m_ItemsArray
.Count
;
514 object[] allValues
= (object[])Array
.CreateInstance(type
, cnt
);
515 for (int i
= 0; i
< cnt
; i
++)
516 allValues
[i
] = BaseGet(i
);
521 protected string BaseGetKey(int index
)
523 return ((_Item
)m_ItemsArray
[index
]).key
;
527 /// Gets a value indicating whether the NameObjectCollectionBase instance contains entries whose keys are not a null reference
529 /// <returns>true if the NameObjectCollectionBase instance contains entries whose keys are not a null reference otherwise, false.</returns>
530 protected bool BaseHasKeys()
532 return (m_ItemsContainer
.Count
> 0);
535 protected void BaseRemove(string name
)
540 throw new NotSupportedException("Collection is read-only");
543 m_ItemsContainer
.Remove(name
);
547 m_NullKeyItem
= null;
550 cnt
= m_ItemsArray
.Count
;
551 for (int i
= 0; i
< cnt
; )
554 if (Equals(key
, name
))
556 m_ItemsArray
.RemoveAt(i
);
567 /// <param name="index"></param>
568 /// <LAME>This function implemented the way Microsoft implemented it -
569 /// 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.
571 /// hashtable is [("Key1","value1")] and array contains [("Key1","value1")("Key1","value2")] then
572 /// after RemoveAt(1) the collection will be in following state:
574 /// array: [("Key1","value1")]
575 /// It's ok only then the key is uniquely assosiated with the value
576 /// To fix it a comparsion of objects stored under the same key in the hashtable and in the arraylist should be added
578 protected void BaseRemoveAt(int index
)
581 throw new NotSupportedException("Collection is read-only");
582 string key
= BaseGetKey(index
);
585 // TODO: see LAME description above
586 m_ItemsContainer
.Remove(key
);
589 m_NullKeyItem
= null;
590 m_ItemsArray
.RemoveAt(index
);
594 /// SDK: Sets the value of the entry at the specified index of the NameObjectCollectionBase instance.
596 /// <param name="index"></param>
597 /// <param name="value"></param>
598 protected void BaseSet(int index
, object value)
602 throw new NotSupportedException("Collection is read-only");
604 _Item item
= (_Item
)m_ItemsArray
[index
];
609 /// 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.
611 /// <param name="name">The String key of the entry to set. The key can be a null reference </param>
612 /// <param name="value">The Object that represents the new value of the entry to set. The value can be a null reference</param>
613 protected void BaseSet(string name
, object value)
617 throw new NotSupportedException("Collection is read-only");
619 _Item item
= FindFirstMatchedItem(name
);
623 BaseAdd(name
, value);
626 private _Item
FindFirstMatchedItem(string name
)
629 return (_Item
)m_ItemsContainer
[name
];
632 //TODO: consider null key case
633 return m_NullKeyItem
;
637 internal bool Equals(string s1
, string s2
)
640 if (m_comparer
!= null)
641 return (m_comparer
.Compare (s1
, s2
) == 0);
643 return equality_comparer
.Equals (s1
, s2
);
645 return (m_comparer
.Compare(s1
, s2
) == 0);