NameObjectCollectionBase.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /**
  2. * System.Collections.Specialized.NamaValueCollection class implementation
  3. *
  4. * Author: Gleb Novodran
  5. */
  6. using System;
  7. using System.Collections;
  8. using System.Runtime.Serialization;
  9. namespace System.Collections.Specialized
  10. {
  11. [Serializable]
  12. public abstract class NameObjectCollectionBase : ICollection, IEnumerable, ISerializable, IDeserializationCallback
  13. {
  14. private Hashtable m_ItemsContainer;
  15. /// <summary>
  16. /// Extends Hashtable based Items container to support storing null-key pairs
  17. /// </summary>
  18. private _Item m_NullKeyItem;
  19. private ArrayList m_ItemsArray;
  20. private IHashCodeProvider m_hashprovider;
  21. private IComparer m_comparer;
  22. private int m_defCapacity;
  23. private bool m_readonly;
  24. internal IComparer Comparer {
  25. get {return m_comparer;}
  26. }
  27. internal IHashCodeProvider HashCodeProvider {
  28. get {return m_hashprovider;}
  29. }
  30. internal protected /*?*/ class _Item
  31. {
  32. public string key;
  33. public object value;
  34. public _Item(string key, object value)
  35. {
  36. this.key = key;
  37. this.value = value;
  38. }
  39. }
  40. /// <summary>
  41. /// Implements IEnumerable interface for KeysCollection
  42. /// </summary>
  43. [Serializable]
  44. internal protected /*?*/ class _KeysEnumerator : IEnumerator
  45. {
  46. private NameObjectCollectionBase m_collection;
  47. private int m_position;
  48. /*private*/internal _KeysEnumerator(NameObjectCollectionBase collection)
  49. {
  50. m_collection = collection;
  51. Reset();
  52. }
  53. public object Current
  54. {
  55. get{
  56. if ((m_position<m_collection.Count)||(m_position<0))
  57. return m_collection.BaseGetKey(m_position);
  58. else
  59. throw new InvalidOperationException();
  60. }
  61. }
  62. public bool MoveNext()
  63. {
  64. return ((++m_position)<m_collection.Count)?true:false;
  65. }
  66. public void Reset()
  67. {
  68. m_position = -1;
  69. }
  70. }
  71. /// <summary>
  72. /// SDK: Represents a collection of the String keys of a collection.
  73. /// </summary>
  74. public class KeysCollection : ICollection, IEnumerable
  75. {
  76. private NameObjectCollectionBase m_collection;
  77. internal/*protected?*/ KeysCollection(NameObjectCollectionBase collection)
  78. {
  79. this.m_collection = collection;
  80. }
  81. public virtual string Get( int index )
  82. {
  83. return m_collection.BaseGetKey(index);
  84. //throw new Exception("Not implemented yet");
  85. }
  86. // ICollection methods -----------------------------------
  87. /// <summary>
  88. ///
  89. /// </summary>
  90. /// <param name="arr"></param>
  91. /// <param name="index"></param>
  92. public virtual void /*ICollection*/ CopyTo(Array arr, int index)
  93. {
  94. if (arr==null)
  95. throw new ArgumentNullException("array can't be null");
  96. IEnumerator en = this.GetEnumerator();
  97. int i = index;
  98. while (en.MoveNext())
  99. {
  100. arr.SetValue(en.Current,i);
  101. i++;
  102. }
  103. }
  104. public virtual bool IsSynchronized
  105. {
  106. get{
  107. throw new Exception("Not implemented yet");
  108. }
  109. }
  110. public virtual object SyncRoot
  111. {
  112. get{
  113. throw new Exception("Not implemented yet");
  114. }
  115. }
  116. /// <summary>
  117. /// Gets the number of keys in the NameObjectCollectionBase.KeysCollection
  118. /// </summary>
  119. public int Count
  120. {
  121. get{
  122. return m_collection.Count;
  123. //throw new Exception("Not implemented yet");
  124. }
  125. }
  126. [MonoTODO]
  127. public string this [int index] {
  128. get { throw new NotImplementedException (); }
  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. throw new Exception("Not implemented yet");
  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 /*ISerializable*/ GetObjectData( SerializationInfo info, StreamingContext context )
  227. {
  228. throw new Exception("Not implemented yet");
  229. }
  230. // ICollection
  231. public virtual int Count
  232. {
  233. get{
  234. return m_ItemsArray.Count;
  235. //throw new Exception("Not implemented yet");
  236. }
  237. }
  238. bool ICollection.IsSynchronized
  239. {
  240. get { return false; }
  241. }
  242. object ICollection.SyncRoot
  243. {
  244. get { return this; }
  245. }
  246. void ICollection.CopyTo (Array array, int index)
  247. {
  248. throw new NotImplementedException ();
  249. }
  250. // IDeserializationCallback
  251. public virtual void OnDeserialization( object sender)
  252. {
  253. throw new Exception("Not implemented yet");
  254. }
  255. //--------------- Protected Instance Properties ----------------
  256. /// <summary>
  257. /// SDK: Gets or sets a value indicating whether the NameObjectCollectionBase instance is read-only.
  258. /// </summary>
  259. protected bool IsReadOnly
  260. {
  261. get{
  262. return m_readonly;
  263. }
  264. set{
  265. m_readonly=value;
  266. }
  267. }
  268. //--------------- Protected Instance Methods -------------------
  269. /// <summary>
  270. /// Adds an Item with the specified key and value into the <see cref="NameObjectCollectionBase"/>NameObjectCollectionBase instance.
  271. /// </summary>
  272. /// <param name="name"></param>
  273. /// <param name="value"></param>
  274. protected void BaseAdd( string name, object value )
  275. {
  276. if (this.IsReadOnly)
  277. throw new NotSupportedException("Collection is read-only");
  278. _Item newitem=new _Item(name, value);
  279. if (name==null){
  280. //todo: consider nullkey entry
  281. if (m_NullKeyItem==null)
  282. m_NullKeyItem = newitem;
  283. }
  284. else
  285. if (m_ItemsContainer[name]==null){
  286. m_ItemsContainer.Add(name,newitem);
  287. }
  288. m_ItemsArray.Add(newitem);
  289. // throw new Exception("Not implemented yet");
  290. }
  291. protected void BaseClear()
  292. {
  293. if (this.IsReadOnly)
  294. throw new NotSupportedException("Collection is read-only");
  295. Init();
  296. //throw new Exception("Not implemented yet");
  297. }
  298. /// <summary>
  299. /// SDK: Gets the value of the entry at the specified index of the NameObjectCollectionBase instance.
  300. /// </summary>
  301. /// <param name="index"></param>
  302. /// <returns></returns>
  303. protected object BaseGet( int index )
  304. {
  305. return ((_Item)m_ItemsArray[index]).value;
  306. //throw new Exception("Not implemented yet");
  307. }
  308. /// <summary>
  309. /// SDK: Gets the value of the first entry with the specified key from the NameObjectCollectionBase instance.
  310. /// </summary>
  311. /// <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>
  312. /// <param name="name"></param>
  313. /// <returns></returns>
  314. protected object BaseGet( string name )
  315. {
  316. _Item item = FindFirstMatchedItem(name);
  317. /// 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.
  318. if (item==null)
  319. return null;
  320. else
  321. return item.value;
  322. }
  323. /// <summary>
  324. /// SDK:Returns a String array that contains all the keys in the NameObjectCollectionBase instance.
  325. /// </summary>
  326. /// <returns>A String array that contains all the keys in the NameObjectCollectionBase instance.</returns>
  327. protected string[] BaseGetAllKeys()
  328. {
  329. int cnt = m_ItemsArray.Count;
  330. string[] allKeys = new string[cnt];
  331. for(int i=0; i<cnt; i++)
  332. allKeys[i] = BaseGetKey(i);//((_Item)m_ItemsArray[i]).key;
  333. return allKeys;
  334. }
  335. /// <summary>
  336. /// SDK: Returns an Object array that contains all the values in the NameObjectCollectionBase instance.
  337. /// </summary>
  338. /// <returns>An Object array that contains all the values in the NameObjectCollectionBase instance.</returns>
  339. protected object[] BaseGetAllValues()
  340. {
  341. int cnt = m_ItemsArray.Count;
  342. object[] allValues = new object[cnt];
  343. for(int i=0; i<cnt; i++)
  344. allValues[i] = BaseGet(i);
  345. return allValues;
  346. // throw new Exception("Not implemented yet");
  347. }
  348. [MonoTODO]
  349. protected object[] BaseGetAllValues( Type type )
  350. {
  351. if (type == null)
  352. throw new ArgumentNullException("'type' argument can't be null");
  353. // TODO: implements this
  354. throw new Exception("Not implemented yet");
  355. }
  356. protected string BaseGetKey( int index )
  357. {
  358. return ((_Item)m_ItemsArray[index]).key;
  359. //throw new Exception("Not implemented yet");
  360. }
  361. /// <summary>
  362. /// Gets a value indicating whether the NameObjectCollectionBase instance contains entries whose keys are not a null reference
  363. /// </summary>
  364. /// <returns>true if the NameObjectCollectionBase instance contains entries whose keys are not a null reference otherwise, false.</returns>
  365. protected bool BaseHasKeys()
  366. {
  367. return (m_ItemsContainer.Count>0);
  368. // throw new Exception("Not implemented yet");
  369. }
  370. /// <summary>
  371. ///
  372. /// </summary>
  373. /// <param name="name"></param>
  374. [MonoTODO]
  375. protected void BaseRemove( string name )
  376. {
  377. int cnt = 0;
  378. String key;
  379. if (this.IsReadOnly)
  380. throw new NotSupportedException("Collection is read-only");
  381. if (name!=null)
  382. {
  383. m_ItemsContainer.Remove(name);
  384. }
  385. else {
  386. m_NullKeyItem = null;
  387. }
  388. cnt = m_ItemsArray.Count;
  389. for (int i=0 ; i< cnt; ){
  390. key=BaseGetKey(i);
  391. // TODO: consider case-sensivity
  392. if (String.Compare(key,name)==0){
  393. m_ItemsArray.RemoveAt(i);
  394. cnt--;
  395. }
  396. else
  397. i++;
  398. }
  399. // throw new Exception("Not implemented yet");
  400. }
  401. /// <summary>
  402. ///
  403. /// </summary>
  404. /// <param name="index"></param>
  405. /// <LAME>This function implemented the way Microsoft implemented it -
  406. /// 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.
  407. /// E.g. if
  408. /// hashtable is [("Key1","value1")] and array contains [("Key1","value1")("Key1","value2")] then
  409. /// after RemoveAt(1) the collection will be in following state:
  410. /// hashtable:[]
  411. /// array: [("Key1","value1")]
  412. /// It's ok only then the key is uniquely assosiated with the value
  413. /// To fix it a comparsion of objects stored under the same key in the hashtable and in the arraylist should be added
  414. /// </LAME>>
  415. [MonoTODO]
  416. protected void BaseRemoveAt( int index )
  417. {
  418. if (this.IsReadOnly)
  419. throw new NotSupportedException("Collection is read-only");
  420. string key = BaseGetKey(index);
  421. if (key!=null){
  422. // TODO: see LAME description above
  423. m_ItemsContainer.Remove(key);
  424. }
  425. else
  426. m_NullKeyItem = null;
  427. m_ItemsArray.RemoveAt(index);
  428. // throw new Exception("Not implemented yet");
  429. }
  430. /// <summary>
  431. /// SDK: Sets the value of the entry at the specified index of the NameObjectCollectionBase instance.
  432. /// </summary>
  433. /// <param name="index"></param>
  434. /// <param name="value"></param>
  435. protected void BaseSet( int index, object value )
  436. {
  437. if (this.IsReadOnly)
  438. throw new NotSupportedException("Collection is read-only");
  439. _Item item = (_Item)m_ItemsArray[index];
  440. item.value = value;
  441. //throw new Exception("Not implemented yet");
  442. }
  443. /// <summary>
  444. /// 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.
  445. /// </summary>
  446. /// <param name="name">The String key of the entry to set. The key can be a null reference </param>
  447. /// <param name="value">The Object that represents the new value of the entry to set. The value can be a null reference</param>
  448. protected void BaseSet( string name, object value )
  449. {
  450. if (this.IsReadOnly)
  451. throw new NotSupportedException("Collection is read-only");
  452. _Item item = FindFirstMatchedItem(name);
  453. if (item!=null)
  454. item.value=value;
  455. else
  456. BaseAdd(name, value);
  457. //throw new Exception("Not implemented yet");
  458. }
  459. [MonoTODO]
  460. private _Item FindFirstMatchedItem(string name)
  461. {
  462. if (name!=null)
  463. return (_Item)m_ItemsContainer[name];
  464. else {
  465. //TODO: consider null key case
  466. return m_NullKeyItem;
  467. //throw new Exception("Not implemented yet");
  468. }
  469. }
  470. //~Object();
  471. }
  472. }