NameObjectCollectionBase.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. //
  2. // System.Collections.Specialized.NameObjectCollectionBase.cs
  3. //
  4. // Author:
  5. // Gleb Novodran
  6. // Andreas Nahr ([email protected])
  7. //
  8. // (C) Ximian, Inc. http://www.ximian.com
  9. //
  10. using System;
  11. using System.Collections;
  12. using System.Runtime.Serialization;
  13. namespace System.Collections.Specialized
  14. {
  15. [Serializable]
  16. public abstract class NameObjectCollectionBase : ICollection, IEnumerable, ISerializable, IDeserializationCallback
  17. {
  18. private Hashtable m_ItemsContainer;
  19. /// <summary>
  20. /// Extends Hashtable based Items container to support storing null-key pairs
  21. /// </summary>
  22. private _Item m_NullKeyItem;
  23. private ArrayList m_ItemsArray;
  24. private IHashCodeProvider m_hashprovider;
  25. private IComparer m_comparer;
  26. private int m_defCapacity;
  27. private bool m_readonly;
  28. SerializationInfo infoCopy;
  29. internal IComparer Comparer {
  30. get {return m_comparer;}
  31. }
  32. internal IHashCodeProvider HashCodeProvider {
  33. get {return m_hashprovider;}
  34. }
  35. internal class _Item
  36. {
  37. public string key;
  38. public object value;
  39. public _Item(string key, object value)
  40. {
  41. this.key = key;
  42. this.value = value;
  43. }
  44. }
  45. /// <summary>
  46. /// Implements IEnumerable interface for KeysCollection
  47. /// </summary>
  48. [Serializable]
  49. internal class _KeysEnumerator : IEnumerator
  50. {
  51. private NameObjectCollectionBase m_collection;
  52. private int m_position;
  53. /*private*/internal _KeysEnumerator(NameObjectCollectionBase collection)
  54. {
  55. m_collection = collection;
  56. Reset();
  57. }
  58. public object Current
  59. {
  60. get{
  61. if ((m_position<m_collection.Count)||(m_position<0))
  62. return m_collection.BaseGetKey(m_position);
  63. else
  64. throw new InvalidOperationException();
  65. }
  66. }
  67. public bool MoveNext()
  68. {
  69. return ((++m_position)<m_collection.Count)?true:false;
  70. }
  71. public void Reset()
  72. {
  73. m_position = -1;
  74. }
  75. }
  76. /// <summary>
  77. /// SDK: Represents a collection of the String keys of a collection.
  78. /// </summary>
  79. [Serializable]
  80. public class KeysCollection : ICollection, IEnumerable
  81. {
  82. private NameObjectCollectionBase m_collection;
  83. internal/*protected?*/ KeysCollection(NameObjectCollectionBase collection)
  84. {
  85. this.m_collection = collection;
  86. }
  87. public virtual string Get( int index )
  88. {
  89. return m_collection.BaseGetKey(index);
  90. //throw new Exception("Not implemented yet");
  91. }
  92. // ICollection methods -----------------------------------
  93. void ICollection.CopyTo(Array arr, int index)
  94. {
  95. if (arr==null)
  96. throw new ArgumentNullException("array can't be null");
  97. IEnumerator en = this.GetEnumerator();
  98. int i = index;
  99. while (en.MoveNext())
  100. {
  101. arr.SetValue(en.Current,i);
  102. i++;
  103. }
  104. }
  105. bool ICollection.IsSynchronized
  106. {
  107. get{
  108. return false;
  109. }
  110. }
  111. object ICollection.SyncRoot
  112. {
  113. get{
  114. return m_collection;
  115. }
  116. }
  117. /// <summary>
  118. /// Gets the number of keys in the NameObjectCollectionBase.KeysCollection
  119. /// </summary>
  120. public int Count
  121. {
  122. get{
  123. return m_collection.Count;
  124. //throw new Exception("Not implemented yet");
  125. }
  126. }
  127. public string this [int index] {
  128. get { return Get (index); }
  129. }
  130. // IEnumerable methods --------------------------------
  131. /// <summary>
  132. /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.KeysCollection.
  133. /// </summary>
  134. /// <returns></returns>
  135. public IEnumerator GetEnumerator()
  136. {
  137. return new _KeysEnumerator(m_collection);
  138. // throw new Exception("Not implemented yet");
  139. }
  140. }
  141. //--------------- Protected Instance Constructors --------------
  142. /// <summary>
  143. /// SDK: Initializes a new instance of the NameObjectCollectionBase class that is empty.
  144. /// </summary>
  145. [MonoTODO]
  146. protected NameObjectCollectionBase():base()
  147. {
  148. m_readonly = false;
  149. m_hashprovider = CaseInsensitiveHashCodeProvider.Default;
  150. m_comparer = CaseInsensitiveComparer.Default;
  151. m_defCapacity = 0;
  152. Init();
  153. /*m_ItemsContainer = new Hashtable(m_hashprovider,m_comparer);
  154. m_ItemsArray = new ArrayList();
  155. m_NullKeyItem = null;*/
  156. //TODO: consider common Reset() method
  157. }
  158. protected NameObjectCollectionBase( int capacity )
  159. {
  160. m_readonly = false;
  161. m_hashprovider = CaseInsensitiveHashCodeProvider.Default;
  162. m_comparer = CaseInsensitiveComparer.Default;
  163. m_defCapacity = capacity;
  164. Init();
  165. /*m_ItemsContainer = new Hashtable(m_defCapacity, m_hashprovider,m_comparer);
  166. m_ItemsArray = new ArrayList();
  167. m_NullKeyItem = null; */
  168. //throw new Exception("Not implemented yet");
  169. }
  170. protected NameObjectCollectionBase( IHashCodeProvider hashProvider, IComparer comparer )
  171. {
  172. m_readonly = false;
  173. m_hashprovider = hashProvider;
  174. m_comparer = comparer;
  175. m_defCapacity = 0;
  176. Init();
  177. /*m_ItemsContainer = new Hashtable(m_hashprovider,m_comparer);
  178. m_ItemsArray = new ArrayList();
  179. m_NullKeyItem = null; */
  180. //throw new Exception("Not implemented yet");
  181. }
  182. protected NameObjectCollectionBase (SerializationInfo info, StreamingContext context)
  183. {
  184. infoCopy = info;
  185. }
  186. protected NameObjectCollectionBase( int capacity, IHashCodeProvider hashProvider, IComparer comparer )
  187. {
  188. m_readonly = false;
  189. m_hashprovider = hashProvider;
  190. m_comparer = comparer;
  191. m_defCapacity = capacity;
  192. Init();
  193. /*m_ItemsContainer = new Hashtable(m_defCapacity,m_hashprovider,m_comparer);
  194. m_ItemsArray = new ArrayList();
  195. m_NullKeyItem = null; */
  196. //throw new Exception("Not implemented yet");
  197. }
  198. private void Init(){
  199. m_ItemsContainer = new Hashtable(m_defCapacity,m_hashprovider,m_comparer);
  200. m_ItemsArray = new ArrayList();
  201. m_NullKeyItem = null;
  202. }
  203. //--------------- Public Instance Properties -------------------
  204. public virtual NameObjectCollectionBase.KeysCollection Keys
  205. {
  206. get
  207. {
  208. return new KeysCollection(this);
  209. //throw new Exception("Not implemented yet");
  210. }
  211. }
  212. //--------------- Public Instance Methods ----------------------
  213. //
  214. /// <summary>
  215. /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.
  216. ///
  217. /// <remark>This enumerator returns the keys of the collection as strings.</remark>
  218. /// </summary>
  219. /// <returns></returns>
  220. public IEnumerator GetEnumerator()
  221. {
  222. return new _KeysEnumerator(this);
  223. }
  224. // GetHashCode
  225. // ISerializable
  226. public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
  227. {
  228. if (info == null)
  229. throw new ArgumentNullException ("info");
  230. int count = Count;
  231. string [] keys = new string [count];
  232. object [] values = new object [count];
  233. int i = 0;
  234. foreach (_Item item in m_ItemsArray) {
  235. keys [i] = item.key;
  236. values [i] = item.value;
  237. i++;
  238. }
  239. info.AddValue ("m_hashprovider", m_hashprovider);
  240. info.AddValue ("m_comparer", m_comparer);
  241. info.AddValue ("m_readonly", m_readonly);
  242. info.AddValue ("keys", keys);
  243. info.AddValue ("values", values);
  244. }
  245. // ICollection
  246. public virtual int Count
  247. {
  248. get{
  249. return m_ItemsArray.Count;
  250. //throw new Exception("Not implemented yet");
  251. }
  252. }
  253. bool ICollection.IsSynchronized
  254. {
  255. get { return false; }
  256. }
  257. object ICollection.SyncRoot
  258. {
  259. get { return this; }
  260. }
  261. void ICollection.CopyTo (Array array, int index)
  262. {
  263. throw new NotImplementedException ();
  264. }
  265. // IDeserializationCallback
  266. public virtual void OnDeserialization (object sender)
  267. {
  268. SerializationInfo info = infoCopy;
  269. if (info == null)
  270. throw new SerializationException ("The object is not a SerializationInfo");
  271. infoCopy = null;
  272. m_hashprovider = (IHashCodeProvider) info.GetValue ("m_hashprovider",
  273. typeof (IHashCodeProvider));
  274. if (m_hashprovider == null)
  275. throw new SerializationException ("The hash provider is null");
  276. m_comparer = (IComparer) info.GetValue ("m_comparer", typeof (IComparer));
  277. if (m_comparer == null)
  278. throw new SerializationException ("The comparer is null");
  279. m_readonly = info.GetBoolean ("m_readonly");
  280. string [] keys = (string []) info.GetValue ("keys", typeof (string []));
  281. if (keys == null)
  282. throw new SerializationException ("keys is null");
  283. object [] values = (object []) info.GetValue ("values", typeof (object []));
  284. if (values == null)
  285. throw new SerializationException ("values is null");
  286. Init ();
  287. int count = keys.Length;
  288. for (int i = 0; i < count; i++)
  289. BaseAdd (keys [i], values [i]);
  290. }
  291. //--------------- Protected Instance Properties ----------------
  292. /// <summary>
  293. /// SDK: Gets or sets a value indicating whether the NameObjectCollectionBase instance is read-only.
  294. /// </summary>
  295. protected bool IsReadOnly
  296. {
  297. get{
  298. return m_readonly;
  299. }
  300. set{
  301. m_readonly=value;
  302. }
  303. }
  304. //--------------- Protected Instance Methods -------------------
  305. /// <summary>
  306. /// Adds an Item with the specified key and value into the <see cref="NameObjectCollectionBase"/>NameObjectCollectionBase instance.
  307. /// </summary>
  308. /// <param name="name"></param>
  309. /// <param name="value"></param>
  310. protected void BaseAdd( string name, object value )
  311. {
  312. if (this.IsReadOnly)
  313. throw new NotSupportedException("Collection is read-only");
  314. _Item newitem=new _Item(name, value);
  315. if (name==null){
  316. //todo: consider nullkey entry
  317. if (m_NullKeyItem==null)
  318. m_NullKeyItem = newitem;
  319. }
  320. else
  321. if (m_ItemsContainer[name]==null){
  322. m_ItemsContainer.Add(name,newitem);
  323. }
  324. m_ItemsArray.Add(newitem);
  325. }
  326. protected void BaseClear()
  327. {
  328. if (this.IsReadOnly)
  329. throw new NotSupportedException("Collection is read-only");
  330. Init();
  331. //throw new Exception("Not implemented yet");
  332. }
  333. /// <summary>
  334. /// SDK: Gets the value of the entry at the specified index of the NameObjectCollectionBase instance.
  335. /// </summary>
  336. /// <param name="index"></param>
  337. /// <returns></returns>
  338. protected object BaseGet( int index )
  339. {
  340. return ((_Item)m_ItemsArray[index]).value;
  341. //throw new Exception("Not implemented yet");
  342. }
  343. /// <summary>
  344. /// SDK: Gets the value of the first entry with the specified key from the NameObjectCollectionBase instance.
  345. /// </summary>
  346. /// <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>
  347. /// <param name="name"></param>
  348. /// <returns></returns>
  349. protected object BaseGet( string name )
  350. {
  351. _Item item = FindFirstMatchedItem(name);
  352. /// 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.
  353. if (item==null)
  354. return null;
  355. else
  356. return item.value;
  357. }
  358. /// <summary>
  359. /// SDK:Returns a String array that contains all the keys in the NameObjectCollectionBase instance.
  360. /// </summary>
  361. /// <returns>A String array that contains all the keys in the NameObjectCollectionBase instance.</returns>
  362. protected string[] BaseGetAllKeys()
  363. {
  364. int cnt = m_ItemsArray.Count;
  365. string[] allKeys = new string[cnt];
  366. for(int i=0; i<cnt; i++)
  367. allKeys[i] = BaseGetKey(i);//((_Item)m_ItemsArray[i]).key;
  368. return allKeys;
  369. }
  370. /// <summary>
  371. /// SDK: Returns an Object array that contains all the values in the NameObjectCollectionBase instance.
  372. /// </summary>
  373. /// <returns>An Object array that contains all the values in the NameObjectCollectionBase instance.</returns>
  374. protected object[] BaseGetAllValues()
  375. {
  376. int cnt = m_ItemsArray.Count;
  377. object[] allValues = new object[cnt];
  378. for(int i=0; i<cnt; i++)
  379. allValues[i] = BaseGet(i);
  380. return allValues;
  381. }
  382. protected object[] BaseGetAllValues( Type type )
  383. {
  384. if (type == null)
  385. throw new ArgumentNullException("'type' argument can't be null");
  386. int cnt = m_ItemsArray.Count;
  387. object[] allValues = (object[]) Array.CreateInstance (type, cnt);
  388. for(int i=0; i<cnt; i++)
  389. allValues[i] = BaseGet(i);
  390. return allValues;
  391. }
  392. protected string BaseGetKey( int index )
  393. {
  394. return ((_Item)m_ItemsArray[index]).key;
  395. //throw new Exception("Not implemented yet");
  396. }
  397. /// <summary>
  398. /// Gets a value indicating whether the NameObjectCollectionBase instance contains entries whose keys are not a null reference
  399. /// </summary>
  400. /// <returns>true if the NameObjectCollectionBase instance contains entries whose keys are not a null reference otherwise, false.</returns>
  401. protected bool BaseHasKeys()
  402. {
  403. return (m_ItemsContainer.Count>0);
  404. // throw new Exception("Not implemented yet");
  405. }
  406. /// <summary>
  407. ///
  408. /// </summary>
  409. /// <param name="name"></param>
  410. [MonoTODO]
  411. protected void BaseRemove( string name )
  412. {
  413. int cnt = 0;
  414. String key;
  415. if (this.IsReadOnly)
  416. throw new NotSupportedException("Collection is read-only");
  417. if (name!=null)
  418. {
  419. m_ItemsContainer.Remove(name);
  420. }
  421. else {
  422. m_NullKeyItem = null;
  423. }
  424. cnt = m_ItemsArray.Count;
  425. for (int i=0 ; i< cnt; ){
  426. key=BaseGetKey(i);
  427. // TODO: consider case-sensivity
  428. if (String.Compare(key,name)==0){
  429. m_ItemsArray.RemoveAt(i);
  430. cnt--;
  431. }
  432. else
  433. i++;
  434. }
  435. // throw new Exception("Not implemented yet");
  436. }
  437. /// <summary>
  438. ///
  439. /// </summary>
  440. /// <param name="index"></param>
  441. /// <LAME>This function implemented the way Microsoft implemented it -
  442. /// 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.
  443. /// E.g. if
  444. /// hashtable is [("Key1","value1")] and array contains [("Key1","value1")("Key1","value2")] then
  445. /// after RemoveAt(1) the collection will be in following state:
  446. /// hashtable:[]
  447. /// array: [("Key1","value1")]
  448. /// It's ok only then the key is uniquely assosiated with the value
  449. /// To fix it a comparsion of objects stored under the same key in the hashtable and in the arraylist should be added
  450. /// </LAME>>
  451. [MonoTODO]
  452. protected void BaseRemoveAt( int index )
  453. {
  454. if (this.IsReadOnly)
  455. throw new NotSupportedException("Collection is read-only");
  456. string key = BaseGetKey(index);
  457. if (key!=null){
  458. // TODO: see LAME description above
  459. m_ItemsContainer.Remove(key);
  460. }
  461. else
  462. m_NullKeyItem = null;
  463. m_ItemsArray.RemoveAt(index);
  464. // throw new Exception("Not implemented yet");
  465. }
  466. /// <summary>
  467. /// SDK: Sets the value of the entry at the specified index of the NameObjectCollectionBase instance.
  468. /// </summary>
  469. /// <param name="index"></param>
  470. /// <param name="value"></param>
  471. protected void BaseSet( int index, object value )
  472. {
  473. if (this.IsReadOnly)
  474. throw new NotSupportedException("Collection is read-only");
  475. _Item item = (_Item)m_ItemsArray[index];
  476. item.value = value;
  477. //throw new Exception("Not implemented yet");
  478. }
  479. /// <summary>
  480. /// 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.
  481. /// </summary>
  482. /// <param name="name">The String key of the entry to set. The key can be a null reference </param>
  483. /// <param name="value">The Object that represents the new value of the entry to set. The value can be a null reference</param>
  484. protected void BaseSet( string name, object value )
  485. {
  486. if (this.IsReadOnly)
  487. throw new NotSupportedException("Collection is read-only");
  488. _Item item = FindFirstMatchedItem(name);
  489. if (item!=null)
  490. item.value=value;
  491. else
  492. BaseAdd(name, value);
  493. //throw new Exception("Not implemented yet");
  494. }
  495. [MonoTODO]
  496. private _Item FindFirstMatchedItem(string name)
  497. {
  498. if (name!=null)
  499. return (_Item)m_ItemsContainer[name];
  500. else {
  501. //TODO: consider null key case
  502. return m_NullKeyItem;
  503. //throw new Exception("Not implemented yet");
  504. }
  505. }
  506. //~Object();
  507. }
  508. }