NameObjectCollectionBase.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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. // IEnumerable methods --------------------------------
  127. /// <summary>
  128. /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.KeysCollection.
  129. /// </summary>
  130. /// <returns></returns>
  131. public IEnumerator GetEnumerator()
  132. {
  133. return new _KeysEnumerator(m_collection);
  134. // throw new Exception("Not implemented yet");
  135. }
  136. }
  137. //--------------- Protected Instance Constructors --------------
  138. /// <summary>
  139. /// SDK: Initializes a new instance of the NameObjectCollectionBase class that is empty.
  140. /// </summary>
  141. [MonoTODO]
  142. protected NameObjectCollectionBase():base()
  143. {
  144. m_readonly = false;
  145. m_hashprovider = CaseInsensitiveHashCodeProvider.Default;
  146. m_comparer = CaseInsensitiveComparer.Default;
  147. m_defCapacity = 0;
  148. Init();
  149. /*m_ItemsContainer = new Hashtable(m_hashprovider,m_comparer);
  150. m_ItemsArray = new ArrayList();
  151. m_NullKeyItem = null;*/
  152. //TODO: consider common Reset() method
  153. }
  154. protected NameObjectCollectionBase( int capacity )
  155. {
  156. m_readonly = false;
  157. m_hashprovider = CaseInsensitiveHashCodeProvider.Default;
  158. m_comparer = CaseInsensitiveComparer.Default;
  159. m_defCapacity = capacity;
  160. Init();
  161. /*m_ItemsContainer = new Hashtable(m_defCapacity, m_hashprovider,m_comparer);
  162. m_ItemsArray = new ArrayList();
  163. m_NullKeyItem = null; */
  164. //throw new Exception("Not implemented yet");
  165. }
  166. protected NameObjectCollectionBase( IHashCodeProvider hashProvider, IComparer comparer )
  167. {
  168. m_readonly = false;
  169. m_hashprovider = hashProvider;
  170. m_comparer = comparer;
  171. m_defCapacity = 0;
  172. Init();
  173. /*m_ItemsContainer = new Hashtable(m_hashprovider,m_comparer);
  174. m_ItemsArray = new ArrayList();
  175. m_NullKeyItem = null; */
  176. //throw new Exception("Not implemented yet");
  177. }
  178. protected NameObjectCollectionBase( SerializationInfo info, StreamingContext context )
  179. {
  180. throw new Exception("Not implemented yet");
  181. }
  182. protected NameObjectCollectionBase( int capacity, IHashCodeProvider hashProvider, IComparer comparer )
  183. {
  184. m_readonly = false;
  185. m_hashprovider = hashProvider;
  186. m_comparer = comparer;
  187. m_defCapacity = capacity;
  188. Init();
  189. /*m_ItemsContainer = new Hashtable(m_defCapacity,m_hashprovider,m_comparer);
  190. m_ItemsArray = new ArrayList();
  191. m_NullKeyItem = null; */
  192. //throw new Exception("Not implemented yet");
  193. }
  194. private void Init(){
  195. m_ItemsContainer = new Hashtable(m_defCapacity,m_hashprovider,m_comparer);
  196. m_ItemsArray = new ArrayList();
  197. m_NullKeyItem = null;
  198. }
  199. //--------------- Public Instance Properties -------------------
  200. public virtual NameObjectCollectionBase.KeysCollection Keys
  201. {
  202. get
  203. {
  204. return new KeysCollection(this);
  205. //throw new Exception("Not implemented yet");
  206. }
  207. }
  208. //--------------- Public Instance Methods ----------------------
  209. //
  210. /// <summary>
  211. /// SDK: Returns an enumerator that can iterate through the NameObjectCollectionBase.
  212. ///
  213. /// <remark>This enumerator returns the keys of the collection as strings.</remark>
  214. /// </summary>
  215. /// <returns></returns>
  216. public IEnumerator GetEnumerator()
  217. {
  218. return new _KeysEnumerator(this);
  219. }
  220. // GetHashCode
  221. // ISerializable
  222. public virtual void /*ISerializable*/ GetObjectData( SerializationInfo info, StreamingContext context )
  223. {
  224. throw new Exception("Not implemented yet");
  225. }
  226. // ICollection
  227. public virtual int Count
  228. {
  229. get{
  230. return m_ItemsArray.Count;
  231. //throw new Exception("Not implemented yet");
  232. }
  233. }
  234. bool ICollection.IsSynchronized
  235. {
  236. get { return false; }
  237. }
  238. object ICollection.SyncRoot
  239. {
  240. get { return this; }
  241. }
  242. void ICollection.CopyTo (Array array, int index)
  243. {
  244. throw new NotImplementedException ();
  245. }
  246. // IDeserializationCallback
  247. public virtual void OnDeserialization( object sender)
  248. {
  249. throw new Exception("Not implemented yet");
  250. }
  251. //--------------- Protected Instance Properties ----------------
  252. /// <summary>
  253. /// SDK: Gets or sets a value indicating whether the NameObjectCollectionBase instance is read-only.
  254. /// </summary>
  255. protected bool IsReadOnly
  256. {
  257. get{
  258. return m_readonly;
  259. }
  260. set{
  261. m_readonly=value;
  262. }
  263. }
  264. //--------------- Protected Instance Methods -------------------
  265. /// <summary>
  266. /// Adds an Item with the specified key and value into the <see cref="NameObjectCollectionBase"/>NameObjectCollectionBase instance.
  267. /// </summary>
  268. /// <param name="name"></param>
  269. /// <param name="value"></param>
  270. protected void BaseAdd( string name, object value )
  271. {
  272. if (this.IsReadOnly)
  273. throw new NotSupportedException("Collection is read-only");
  274. _Item newitem=new _Item(name, value);
  275. if (name==null){
  276. //todo: consider nullkey entry
  277. if (m_NullKeyItem==null)
  278. m_NullKeyItem = newitem;
  279. }
  280. else
  281. if (m_ItemsContainer[name]==null){
  282. m_ItemsContainer.Add(name,newitem);
  283. }
  284. m_ItemsArray.Add(newitem);
  285. // throw new Exception("Not implemented yet");
  286. }
  287. protected void BaseClear()
  288. {
  289. if (this.IsReadOnly)
  290. throw new NotSupportedException("Collection is read-only");
  291. Init();
  292. //throw new Exception("Not implemented yet");
  293. }
  294. /// <summary>
  295. /// SDK: Gets the value of the entry at the specified index of the NameObjectCollectionBase instance.
  296. /// </summary>
  297. /// <param name="index"></param>
  298. /// <returns></returns>
  299. protected object BaseGet( int index )
  300. {
  301. return ((_Item)m_ItemsArray[index]).value;
  302. //throw new Exception("Not implemented yet");
  303. }
  304. /// <summary>
  305. /// SDK: Gets the value of the first entry with the specified key from the NameObjectCollectionBase instance.
  306. /// </summary>
  307. /// <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>
  308. /// <param name="name"></param>
  309. /// <returns></returns>
  310. protected object BaseGet( string name )
  311. {
  312. _Item item = FindFirstMatchedItem(name);
  313. /// 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.
  314. if (item==null)
  315. return null;
  316. else
  317. return item.value;
  318. }
  319. /// <summary>
  320. /// SDK:Returns a String array that contains all the keys in the NameObjectCollectionBase instance.
  321. /// </summary>
  322. /// <returns>A String array that contains all the keys in the NameObjectCollectionBase instance.</returns>
  323. protected string[] BaseGetAllKeys()
  324. {
  325. int cnt = m_ItemsArray.Count;
  326. string[] allKeys = new string[cnt];
  327. for(int i=0; i<cnt; i++)
  328. allKeys[i] = BaseGetKey(i);//((_Item)m_ItemsArray[i]).key;
  329. return allKeys;
  330. }
  331. /// <summary>
  332. /// SDK: Returns an Object array that contains all the values in the NameObjectCollectionBase instance.
  333. /// </summary>
  334. /// <returns>An Object array that contains all the values in the NameObjectCollectionBase instance.</returns>
  335. protected object[] BaseGetAllValues()
  336. {
  337. int cnt = m_ItemsArray.Count;
  338. object[] allValues = new object[cnt];
  339. for(int i=0; i<cnt; i++)
  340. allValues[i] = BaseGet(i);
  341. return allValues;
  342. // throw new Exception("Not implemented yet");
  343. }
  344. [MonoTODO]
  345. protected object[] BaseGetAllValues( Type type )
  346. {
  347. if (type == null)
  348. throw new ArgumentNullException("'type' argument can't be null");
  349. // TODO: implements this
  350. throw new Exception("Not implemented yet");
  351. }
  352. protected string BaseGetKey( int index )
  353. {
  354. return ((_Item)m_ItemsArray[index]).key;
  355. //throw new Exception("Not implemented yet");
  356. }
  357. /// <summary>
  358. /// Gets a value indicating whether the NameObjectCollectionBase instance contains entries whose keys are not a null reference
  359. /// </summary>
  360. /// <returns>true if the NameObjectCollectionBase instance contains entries whose keys are not a null reference otherwise, false.</returns>
  361. protected bool BaseHasKeys()
  362. {
  363. return (m_ItemsContainer.Count>0);
  364. // throw new Exception("Not implemented yet");
  365. }
  366. /// <summary>
  367. ///
  368. /// </summary>
  369. /// <param name="name"></param>
  370. [MonoTODO]
  371. protected void BaseRemove( string name )
  372. {
  373. int cnt = 0;
  374. String key;
  375. if (this.IsReadOnly)
  376. throw new NotSupportedException("Collection is read-only");
  377. if (name!=null)
  378. {
  379. m_ItemsContainer.Remove(name);
  380. }
  381. else {
  382. m_NullKeyItem = null;
  383. }
  384. cnt = m_ItemsArray.Count;
  385. for (int i=0 ; i< cnt; ){
  386. key=BaseGetKey(i);
  387. // TODO: consider case-sensivity
  388. if (String.Compare(key,name)==0){
  389. m_ItemsArray.RemoveAt(i);
  390. cnt--;
  391. }
  392. else
  393. i++;
  394. }
  395. // throw new Exception("Not implemented yet");
  396. }
  397. /// <summary>
  398. ///
  399. /// </summary>
  400. /// <param name="index"></param>
  401. /// <LAME>This function implemented the way Microsoft implemented it -
  402. /// 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.
  403. /// E.g. if
  404. /// hashtable is [("Key1","value1")] and array contains [("Key1","value1")("Key1","value2")] then
  405. /// after RemoveAt(1) the collection will be in following state:
  406. /// hashtable:[]
  407. /// array: [("Key1","value1")]
  408. /// It's ok only then the key is uniquely assosiated with the value
  409. /// To fix it a comparsion of objects stored under the same key in the hashtable and in the arraylist should be added
  410. /// </LAME>>
  411. [MonoTODO]
  412. protected void BaseRemoveAt( int index )
  413. {
  414. if (this.IsReadOnly)
  415. throw new NotSupportedException("Collection is read-only");
  416. string key = BaseGetKey(index);
  417. if (key!=null){
  418. // TODO: see LAME description above
  419. m_ItemsContainer.Remove(key);
  420. }
  421. else
  422. m_NullKeyItem = null;
  423. m_ItemsArray.RemoveAt(index);
  424. // throw new Exception("Not implemented yet");
  425. }
  426. /// <summary>
  427. /// SDK: Sets the value of the entry at the specified index of the NameObjectCollectionBase instance.
  428. /// </summary>
  429. /// <param name="index"></param>
  430. /// <param name="value"></param>
  431. protected void BaseSet( int index, object value )
  432. {
  433. if (this.IsReadOnly)
  434. throw new NotSupportedException("Collection is read-only");
  435. _Item item = (_Item)m_ItemsArray[index];
  436. item.value = value;
  437. //throw new Exception("Not implemented yet");
  438. }
  439. /// <summary>
  440. /// 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.
  441. /// </summary>
  442. /// <param name="name">The String key of the entry to set. The key can be a null reference </param>
  443. /// <param name="value">The Object that represents the new value of the entry to set. The value can be a null reference</param>
  444. protected void BaseSet( string name, object value )
  445. {
  446. if (this.IsReadOnly)
  447. throw new NotSupportedException("Collection is read-only");
  448. _Item item = FindFirstMatchedItem(name);
  449. if (item!=null)
  450. item.value=value;
  451. else
  452. BaseAdd(name, value);
  453. //throw new Exception("Not implemented yet");
  454. }
  455. [MonoTODO]
  456. private _Item FindFirstMatchedItem(string name)
  457. {
  458. if (name!=null)
  459. return (_Item)m_ItemsContainer[name];
  460. else {
  461. //TODO: consider null key case
  462. return m_NullKeyItem;
  463. //throw new Exception("Not implemented yet");
  464. }
  465. }
  466. //~Object();
  467. }
  468. }