PageRenderTime 204ms CodeModel.GetById 75ms app.highlight 70ms RepoModel.GetById 50ms app.codeStats 1ms

/Utilities/Collections/DictionaryBase.cs

#
C# | 1069 lines | 607 code | 95 blank | 367 comment | 30 complexity | 7d1528dd5795ed37e22d307d202e4f0f MD5 | raw file
   1using System;
   2using System.Collections;
   3using System.Collections.Generic;
   4using System.Diagnostics;
   5using System.Text;
   6using NUnit.Framework;
   7
   8namespace Delta.Utilities.Collections
   9{
  10	/// <summary>
  11	/// DictionaryBase is a base class for generics like the .NET 1.1 one.
  12	/// Implements IDictionary&lt;T&gt; and IDictionary.
  13	/// <para />
  14	/// This site contains examples and a great explanation of dictionaries:
  15	/// http://www.dotnetperls.com/dictionary-keys
  16	/// </summary>
  17	/// <typeparam name="TKey">Key type</typeparam>
  18	/// <typeparam name="TValue">Value type</typeparam>
  19	[DebuggerDisplay("{DebuggerToString()}")]
  20	public abstract class DictionaryBase<TKey, TValue>
  21		: CollectionBase<KeyValuePair<TKey, TValue>>,
  22		  IDictionary<TKey, TValue>, IDictionary
  23	{
  24		#region KeysCollection Class
  25		/// <summary>
  26		/// A private class that implements ICollection&lt;TKey&gt; and ICollection
  27		/// for the Keys collection. The collection is read-only.
  28		/// </summary>
  29		/// <returns>Collection base</returns>
  30		private sealed class KeysCollection : CollectionBase<TKey>
  31		{
  32			#region Count (Public)
  33			/// <summary>
  34			/// Count
  35			/// </summary>
  36			/// <returns>Int</returns>
  37			public override int Count
  38			{
  39				get
  40				{
  41					return myDictionary.Count;
  42				} // get
  43			}
  44			#endregion
  45
  46			#region Private
  47
  48			#region myDictionary (Private)
  49			/// <summary>
  50			/// My dictionary
  51			/// </summary>
  52			private readonly DictionaryBase<TKey, TValue> myDictionary;
  53			#endregion
  54
  55			#endregion
  56
  57			#region Constructors
  58			/// <summary>
  59			/// Constructor.
  60			/// </summary>
  61			/// <param name="myDictionary">The dictionary this is associated with.
  62			/// </param>
  63			public KeysCollection(DictionaryBase<TKey, TValue> myDictionary)
  64			{
  65				this.myDictionary = myDictionary;
  66			}
  67			#endregion
  68
  69			#region GetEnumerator (Public)
  70			/// <summary>
  71			/// Get enumerator
  72			/// </summary>
  73			/// <returns>IEnumerator</returns>
  74			public override IEnumerator<TKey> GetEnumerator()
  75			{
  76				foreach (KeyValuePair<TKey, TValue> pair in myDictionary)
  77				{
  78					yield return pair.Key;
  79				}
  80			}
  81			#endregion
  82
  83			#region Contains (Public)
  84			/// <summary>
  85			/// Contains
  86			/// </summary>
  87			/// <param name="key">Key</param>
  88			/// <returns>True if the key was found, false otherwise</returns>
  89			public override bool Contains(TKey key)
  90			{
  91				return myDictionary.ContainsKey(key);
  92			}
  93			#endregion
  94
  95			#region Clear (Public)
  96			/// <summary>
  97			/// Clear
  98			/// </summary>
  99			public override void Clear()
 100			{
 101				throw new Exception("It is not allowed to clear the keys!");
 102			}
 103			#endregion
 104
 105			#region Remove (Public)
 106			/// <summary>
 107			/// Remove. Do not call, this method is not implemented!
 108			/// </summary>
 109			/// <param name="item">Item</param>
 110			/// <returns>True if the item was removed.</returns>
 111			public override bool Remove(TKey item)
 112			{
 113				throw new Exception("It is not allowed to remove an item.");
 114			}
 115			#endregion
 116		}
 117		#endregion
 118
 119		#region ValuesCollection Class
 120		/// <summary>
 121		/// A private class that implements ICollection&lt;TValue&gt; and
 122		/// ICollection for the Values collection. The collection is read-only.
 123		/// </summary>
 124		/// <returns>Collection base</returns>
 125		private sealed class ValuesCollection : CollectionBase<TValue>
 126		{
 127			#region Count (Public)
 128			/// <summary>
 129			/// Count
 130			/// </summary>
 131			/// <returns>Int</returns>
 132			public override int Count
 133			{
 134				get
 135				{
 136					return myDictionary.Count;
 137				} // get
 138			}
 139			#endregion
 140
 141			#region Private
 142
 143			#region myDictionary (Private)
 144			/// <summary>
 145			/// My dictionary
 146			/// </summary>
 147			private readonly DictionaryBase<TKey, TValue> myDictionary;
 148			#endregion
 149
 150			#endregion
 151
 152			#region Constructors
 153			/// <summary>
 154			/// Create values collection
 155			/// </summary>
 156			/// <param name="myDictionary">My dictionary</param>
 157			public ValuesCollection(DictionaryBase<TKey, TValue> myDictionary)
 158			{
 159				this.myDictionary = myDictionary;
 160			}
 161			#endregion
 162
 163			#region GetEnumerator (Public)
 164			/// <summary>
 165			/// Get enumerator
 166			/// </summary>
 167			/// <returns>IEnumerator</returns>
 168			public override IEnumerator<TValue> GetEnumerator()
 169			{
 170				foreach (KeyValuePair<TKey, TValue> pair in myDictionary)
 171				{
 172					yield return pair.Value;
 173				}
 174			}
 175			#endregion
 176
 177			#region Clear (Public)
 178			/// <summary>
 179			/// Clear
 180			/// </summary>
 181			public override void Clear()
 182			{
 183				throw new Exception("It is not allowed to clear the values!");
 184			}
 185			#endregion
 186
 187			#region Remove (Public)
 188			/// <summary>
 189			/// Remove. Do not call, this method is not implemented!
 190			/// </summary>
 191			/// <param name="item">Item</param>
 192			/// <returns>True if removing the item succeeded.</returns>
 193			public override bool Remove(TValue item)
 194			{
 195				throw new Exception("It is not allowed to remove an item.");
 196			}
 197			#endregion
 198		}
 199		#endregion
 200
 201		#region DictionaryEnumeratorWrapper Class
 202		/// <summary>
 203		/// A class that wraps a IDictionaryEnumerator around an IEnumerator that
 204		/// enumerates KeyValuePairs. This is useful in implementing IDictionary,
 205		/// because IEnumerator can be implemented with an iterator, but
 206		/// IDictionaryEnumerator cannot.
 207		/// </summary>
 208		/// <returns>IDictionary enumerator</returns>
 209		private class DictionaryEnumeratorWrapper : IDictionaryEnumerator
 210		{
 211			#region Entry (Public)
 212			/// <summary>
 213			/// Entry
 214			/// </summary>
 215			/// <returns>Dictionary entry</returns>
 216			public DictionaryEntry Entry
 217			{
 218				get
 219				{
 220					KeyValuePair<TKey, TValue> pair = enumerator.Current;
 221					DictionaryEntry entry = new DictionaryEntry();
 222					if (pair.Key != null)
 223					{
 224						entry.Key = pair.Key;
 225					}
 226					entry.Value = pair.Value;
 227
 228					return entry;
 229				}
 230			}
 231			#endregion
 232
 233			#region Key (Public)
 234			/// <summary>
 235			/// Key
 236			/// </summary>
 237			/// <returns>Object</returns>
 238			public object Key
 239			{
 240				get
 241				{
 242					KeyValuePair<TKey, TValue> pair = enumerator.Current;
 243
 244					return pair.Key;
 245				}
 246			}
 247			#endregion
 248
 249			#region Value (Public)
 250			/// <summary>
 251			/// Value
 252			/// </summary>
 253			/// <returns>Object</returns>
 254			public object Value
 255			{
 256				get
 257				{
 258					KeyValuePair<TKey, TValue> pair = enumerator.Current;
 259					return pair.Value;
 260				}
 261			}
 262			#endregion
 263
 264			#region Current (Public)
 265			/// <summary>
 266			/// Current
 267			/// </summary>
 268			/// <returns>Object</returns>
 269			public object Current
 270			{
 271				get
 272				{
 273					return Entry;
 274				}
 275			}
 276			#endregion
 277
 278			#region Private
 279
 280			#region enumerator (Private)
 281			/// <summary>
 282			/// Enumerator
 283			/// </summary>
 284			private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
 285			#endregion
 286
 287			#endregion
 288
 289			#region Constructors
 290			/// <summary>
 291			/// Constructor.
 292			/// </summary>
 293			/// <param name="enumerator">
 294			/// The enumerator of KeyValuePairs that is being wrapped.
 295			/// </param>
 296			public DictionaryEnumeratorWrapper(
 297				IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
 298			{
 299				this.enumerator = enumerator;
 300			}
 301			#endregion
 302
 303			#region IEnumerator Members
 304			/// <summary>
 305			/// Move next
 306			/// </summary>
 307			/// <returns>True if there is a next item for the enumerator.</returns>
 308			public bool MoveNext()
 309			{
 310				return enumerator.MoveNext();
 311			}
 312
 313			/// <summary>
 314			/// Reset. Do not call, this method is not implemented!
 315			/// </summary>
 316			public void Reset()
 317			{
 318				throw new NotSupportedException(
 319					"Reset is not supported on this enumerator.");
 320			}
 321			#endregion
 322		}
 323		#endregion
 324
 325		#region Item (Public)
 326		/// <summary>
 327		/// The indexer of the dictionary. This is used to store keys and values
 328		/// and retrieve values from the dictionary. The setter accessor must be
 329		/// overridden in the derived class.
 330		/// </summary>
 331		/// <param name="key">Key to find in the dictionary.</param>
 332		/// <returns>The value associated with the key.</returns>
 333		/// <exception cref="KeyNotFoundException">Thrown from the get accessor
 334		/// if the key was not found in the dictionary.</exception>
 335		public virtual TValue this[TKey key]
 336		{
 337			get
 338			{
 339				TValue value;
 340				if (TryGetValue(key, out value))
 341				{
 342					return value;
 343				}
 344				else
 345				{
 346					throw new KeyNotFoundException(
 347						"The key was not found in the collection.");
 348				}
 349			}
 350
 351			set
 352			{
 353				throw new NotSupportedException(
 354					"The set accessor of the indexer must be overridden.");
 355			}
 356		}
 357		#endregion
 358
 359		#region Keys (Public)
 360		/// <summary>
 361		/// Returns a collection of the keys in this dictionary. 
 362		/// </summary>
 363		/// <value>A read-only collection of the keys in this dictionary.</value>
 364		public virtual ICollection<TKey> Keys
 365		{
 366			get
 367			{
 368				return new KeysCollection(this);
 369			} // get
 370		}
 371		#endregion
 372
 373		#region Values (Public)
 374		/// <summary>
 375		/// Returns a collection of the values in this dictionary. The ordering of 
 376		/// values in this collection is the same as that in the Keys collection.
 377		/// </summary>
 378		/// <value>A read-only collection of the values in this dictionary.</value>
 379		public virtual ICollection<TValue> Values
 380		{
 381			get
 382			{
 383				return new ValuesCollection(this);
 384			} // get
 385		}
 386		#endregion
 387
 388		#region Private
 389
 390		#region IsFixedSize (Private)
 391		/// <summary>
 392		/// Returns whether this dictionary is fixed size.
 393		/// This implemented always returns false.
 394		/// </summary>
 395		/// <typeparam name="TKey">TKey</typeparam>
 396		/// <typeparam name="TValue">TValue</typeparam>
 397		/// <value>Always returns false.</value>
 398		bool IDictionary.IsFixedSize
 399		{
 400			get
 401			{
 402				return false;
 403			} // get
 404		}
 405		#endregion
 406
 407		#region IsReadOnly (Private)
 408		/// <summary>
 409		/// Returns if this dictionary is read-only.
 410		/// This implementation always returns false.
 411		/// </summary>
 412		/// <typeparam name="TKey">TKey</typeparam>
 413		/// <typeparam name="TValue">TValue</typeparam>
 414		/// <value>Always returns false.</value>
 415		bool IDictionary.IsReadOnly
 416		{
 417			get
 418			{
 419				return false;
 420			} // get
 421		}
 422		#endregion
 423
 424		#region Keys (Private)
 425		/// <summary>
 426		/// Returns a collection of all the keys in the dictionary. The values in
 427		/// this collection will be enumerated in the same order as the
 428		/// (overridden) GetEnumerator method.
 429		/// </summary>
 430		/// <typeparam name="TKey">TKey</typeparam>
 431		/// <typeparam name="TValue">TValue</typeparam>
 432		/// <value>The collection of keys.</value>
 433		ICollection IDictionary.Keys
 434		{
 435			get
 436			{
 437				return new KeysCollection(this);
 438			} // get
 439		}
 440		#endregion
 441
 442		#region Values (Private)
 443		/// <summary>
 444		/// Returns a collection of all the values in the dictionary. The values
 445		/// in this collection will be enumerated in the same order as the
 446		/// (overridden) GetEnumerator method.
 447		/// </summary>
 448		/// <typeparam name="TKey">TKey</typeparam>
 449		/// <typeparam name="TValue">TValue</typeparam>
 450		/// <value>The collection of values.</value>
 451		ICollection IDictionary.Values
 452		{
 453			get
 454			{
 455				return new ValuesCollection(this);
 456			} // get
 457		}
 458		#endregion
 459
 460		#region Item (Private)
 461		/// <summary>
 462		/// Gets or sets the value associated with a given key. When getting a
 463		/// value, if this key is not found in the collection, then null is
 464		/// returned. When setting a value, the value replaces any existing value
 465		/// in the dictionary. If either the key or value are not of the correct
 466		/// type for this dictionary, an ArgumentException is thrown.
 467		/// </summary>
 468		/// <value>The value associated with the key, or null if the key was not
 469		/// present.</value>
 470		/// <exception cref="ArgumentException">Key could not be converted to TKey,
 471		/// or value could not be converted to TValue.</exception>
 472		object IDictionary.this[object key]
 473		{
 474			get
 475			{
 476				if (key is TKey ||
 477				    key == null)
 478				{
 479					TKey theKey = (TKey)key;
 480					TValue theValue;
 481
 482					// The IDictionary (non-generic) indexer returns null for not found,
 483					// instead of throwing an exception like the generic IDictionary
 484					// indexer.
 485					if (TryGetValue(theKey, out theValue))
 486					{
 487						return theValue;
 488					}
 489					else
 490					{
 491						return null;
 492					}
 493				}
 494				else
 495				{
 496					return null;
 497				}
 498			}
 499			set
 500			{
 501				CheckGenericType<TKey>("key", key);
 502				CheckGenericType<TValue>("value", value);
 503				this[(TKey)key] = (TValue)value;
 504			}
 505		}
 506		#endregion
 507
 508		#endregion
 509
 510		#region ICollection<KeyValuePair<TKey,TValue>> Members
 511		/// <summary>
 512		/// Adds a key-value pair to the collection. This implementation calls the
 513		/// Add method with the Key and Value from the item.
 514		/// </summary>
 515		/// <param name="item">
 516		/// A KeyValuePair contains the Key and Value to add.
 517		/// </param>
 518		public override void Add(KeyValuePair<TKey, TValue> item)
 519		{
 520			Add(item.Key, item.Value);
 521		}
 522
 523		/// <summary>
 524		/// Clears the dictionary.
 525		/// This method must be overridden in the derived class.
 526		/// </summary>
 527		public abstract override void Clear();
 528
 529		/// <summary>
 530		/// Determines if a dictionary contains a given KeyValuePair. This
 531		/// implementation checks to see if the dictionary contains the given key,
 532		/// and if the value associated with the key is equal to (via
 533		/// object.Equals) the value.
 534		/// </summary>
 535		/// <param name="item">
 536		/// A KeyValuePair containing the Key and Value to check for.
 537		/// </param>
 538		/// <returns>True if the item was found, false otherwise.</returns>
 539		public override bool Contains(KeyValuePair<TKey, TValue> item)
 540		{
 541			if (ContainsKey(item.Key))
 542			{
 543				return (Equals(this[item.Key], item.Value));
 544			}
 545			else
 546			{
 547				return false;
 548			}
 549		}
 550
 551		/// <summary>
 552		/// Determines if a dictionary contains a given KeyValuePair, and if so,
 553		/// removes it. This implementation checks to see if the dictionary
 554		/// contains the given key, and if the value associated with the key is
 555		/// equal to (via object.Equals) the value. If so, the key-value pair is
 556		/// removed.
 557		/// </summary>
 558		/// <param name="item">
 559		/// A KeyValuePair containing the Key and Value to check for.
 560		/// </param>
 561		/// <returns>
 562		/// True if the item was found and removed. False otherwise.
 563		/// </returns>
 564		public override bool Remove(KeyValuePair<TKey, TValue> item)
 565		{
 566			if (((ICollection<KeyValuePair<TKey, TValue>>)this).Contains(item))
 567			{
 568				return Remove(item.Key);
 569			}
 570			else
 571			{
 572				return false;
 573			}
 574		}
 575		#endregion
 576
 577		#region IDictionary Members
 578		/// <summary>
 579		/// Adds a key-value pair to the collection. If key or value are not of
 580		/// the expected types, an ArgumentException is thrown. If both key and
 581		/// value are of the expected types, the (overridden) Add method is called
 582		/// with the key and value to add.
 583		/// </summary>
 584		/// <param name="key">Key to add</param>
 585		/// <param name="value">Value to add</param>
 586		/// <exception cref="ArgumentException">Key or value are not of the
 587		/// expected type for this dictionary.</exception>
 588		void IDictionary.Add(object key, object value)
 589		{
 590			CheckGenericType<TKey>("key", key);
 591			CheckGenericType<TValue>("value", value);
 592			Add((TKey)key, (TValue)value);
 593		}
 594
 595		/// <summary>
 596		/// Clears this dictionary. Calls the (overridden) Clear method.
 597		/// </summary>
 598		void IDictionary.Clear()
 599		{
 600			Clear();
 601		}
 602
 603		/// <summary>
 604		/// Determines if this dictionary contains a key equal to
 605		/// <paramref name="key"/>. The dictionary is not changed. Calls the
 606		/// (overridden) ContainsKey method. If key is not of the correct TKey for
 607		/// the dictionary, false is returned.
 608		/// </summary>
 609		/// <param name="key">The key to search for.</param>
 610		/// <returns>True if the dictionary contains key. False if the dictionary
 611		/// does not contain key.</returns>
 612		bool IDictionary.Contains(object key)
 613		{
 614			if (key is TKey ||
 615			    key == null)
 616			{
 617				return ContainsKey((TKey)key);
 618			}
 619			else
 620			{
 621				return false;
 622			}
 623		}
 624
 625		/// <summary>
 626		/// Returns an enumerator that enumerates all entries in the dictionary.
 627		/// Each entry is returned as a DictionaryEntry. The entries are enumerated
 628		/// in the same orders as the (overridden) GetEnumerator method.
 629		/// </summary>
 630		/// <returns>An enumerator for enumerating all the elements in the
 631		/// OrderedDictionary.</returns>		
 632		IDictionaryEnumerator IDictionary.GetEnumerator()
 633		{
 634			// You can't implement this directly with an iterator, because iterators
 635			// automatically implement IEnumerator, not IDictionaryEnumerator.
 636			// We use the helper class DictionaryEnumeratorWrapper.
 637			return new DictionaryEnumeratorWrapper(GetEnumerator());
 638		}
 639
 640		/// <summary>
 641		/// Removes the key (and associated value) from the collection that is
 642		/// equal to the passed in key. If no key in the dictionary is equal to
 643		/// the passed key, the dictionary is unchanged. Calls the (overridden)
 644		/// Remove method. If key is not of the correct TKey for the dictionary,
 645		/// the dictionary is unchanged.
 646		/// </summary>
 647		/// <param name="key">The key to remove.</param>
 648		/// <exception cref="ArgumentException">key could not be converted to TKey.
 649		/// </exception>
 650		void IDictionary.Remove(object key)
 651		{
 652			if (key is TKey ||
 653			    key == null)
 654			{
 655				Remove((TKey)key);
 656			}
 657		}
 658		#endregion
 659
 660		#region IDictionary<TKey,TValue> Members
 661		/// <summary>
 662		/// Adds a new key-value pair to the dictionary. 
 663		/// </summary>
 664		/// <remarks>The default implementation of this method
 665		/// checks to see if the key already exists using 
 666		/// ContainsKey, then calls the indexer setter if the key doesn't
 667		/// already exist. </remarks>
 668		/// <param name="key">Key to add.</param>
 669		/// <param name="value">Value to associated with the key.</param>
 670		/// <exception cref="ArgumentException">key is already present in the
 671		/// dictionary</exception>
 672		public virtual void Add(TKey key, TValue value)
 673		{
 674			if (ContainsKey(key))
 675			{
 676				throw new ArgumentException(
 677					"The key was already present in the dictionary.", "key");
 678			}
 679			else
 680			{
 681				this[key] = value;
 682			}
 683		}
 684
 685		/// <summary>
 686		/// Determines whether a given key is found in the dictionary.
 687		/// </summary>
 688		/// <remarks>The default implementation simply calls TryGetValue and
 689		/// returns what it returns.</remarks>
 690		/// <param name="key">Key to look for in the dictionary.</param>
 691		/// <returns>True if the key is present in the dictionary.</returns>
 692		public virtual bool ContainsKey(TKey key)
 693		{
 694			TValue dummy;
 695			return TryGetValue(key, out dummy);
 696		}
 697
 698		/// <summary>
 699		/// Removes a key from the dictionary.
 700		/// This method must be overridden in the derived class.
 701		/// </summary>
 702		/// <param name="key">Key to remove from the dictionary.</param>
 703		/// <returns>True if the key was found, false otherwise.</returns>
 704		public abstract bool Remove(TKey key);
 705
 706		/// <summary>
 707		/// Determines if this dictionary contains a key equal to
 708		/// <paramref name="key"/>. If so, the value associated with that key is
 709		/// returned through the value parameter. This method must be overridden
 710		/// by the derived class.
 711		/// </summary>
 712		/// <param name="key">The key to search for.</param>
 713		/// <param name="value">Returns the value associated with key, if true was
 714		/// returned.</param>
 715		/// <returns>True if the dictionary contains key. False if the dictionary
 716		/// does not contain key.</returns>
 717		public abstract bool TryGetValue(TKey key, out TValue value);
 718		#endregion
 719
 720		#region IEnumerable Members
 721		/// <summary>
 722		/// Returns an enumerator that enumerates all entries in the dictionary.
 723		/// Each entry is returned as a DictionaryEntry. The entries are enumerated
 724		/// in the same orders as the (overridden) GetEnumerator method.
 725		/// </summary>
 726		/// <returns>An enumerator for enumerating all the elements in the
 727		/// OrderedDictionary.</returns>		
 728		IEnumerator IEnumerable.GetEnumerator()
 729		{
 730			return ((IDictionary)this).GetEnumerator();
 731		}
 732		#endregion
 733
 734		#region ToString (Public)
 735		/// <summary>
 736		/// Shows the string representation of the dictionary. The string
 737		/// representation contains a list of the mappings in the dictionary.
 738		/// </summary>
 739		/// <returns>The string representation of the dictionary.</returns>
 740		public override string ToString()
 741		{
 742			bool firstItem = true;
 743
 744			StringBuilder builder = new StringBuilder();
 745
 746			builder.Append("{");
 747
 748			// Call ToString on each item and put it in.
 749			foreach (KeyValuePair<TKey, TValue> pair in this)
 750			{
 751				if (!firstItem)
 752				{
 753					builder.Append(", ");
 754				}
 755
 756				if (pair.Key == null)
 757				{
 758					builder.Append("null");
 759				}
 760				else
 761				{
 762					builder.Append(pair.Key.ToString());
 763				}
 764
 765				builder.Append("->");
 766
 767				if (pair.Value == null)
 768				{
 769					builder.Append("null");
 770				}
 771				else
 772				{
 773					builder.Append(pair.Value.ToString());
 774				}
 775
 776				firstItem = false;
 777			}
 778
 779			builder.Append("}");
 780			return builder.ToString();
 781		}
 782		#endregion
 783
 784		#region Methods (Private)
 785
 786		#region DebuggerToString
 787		/// <summary>
 788		/// Display the contents of the dictionary in the debugger. This is
 789		/// intentionally private, it is called only from the debugger due to the
 790		/// presence of the DebuggerDisplay attribute. It is similar format to
 791		/// ToString(), but is limited to 250-300 characters or so, so as not to
 792		/// overload the debugger.
 793		/// </summary>
 794		/// <returns>The string representation of the items in the collection,
 795		/// similar in format to ToString().</returns>
 796		internal new string DebuggerToString()
 797		{
 798			const int MAXLENGTH = 250;
 799
 800			bool firstItem = true;
 801
 802			StringBuilder builder = new StringBuilder();
 803
 804			builder.Append("{");
 805
 806			// Call ToString on each item and put it in.
 807			foreach (KeyValuePair<TKey, TValue> pair in this)
 808			{
 809				if (builder.Length >= MAXLENGTH)
 810				{
 811					builder.Append(", ...");
 812					break;
 813				}
 814
 815				if (!firstItem)
 816				{
 817					builder.Append(", ");
 818				}
 819
 820				if (pair.Key == null)
 821				{
 822					builder.Append("null");
 823				}
 824				else
 825				{
 826					builder.Append(pair.Key.ToString());
 827				}
 828
 829				builder.Append("->");
 830
 831				if (pair.Value == null)
 832				{
 833					builder.Append("null");
 834				}
 835				else
 836				{
 837					builder.Append(pair.Value.ToString());
 838				}
 839
 840				firstItem = false;
 841			}
 842
 843			builder.Append("}");
 844			return builder.ToString();
 845		}
 846		#endregion
 847
 848		#region CheckGenericType
 849		/// <summary>
 850		/// Check that the given parameter is of the expected generic type.
 851		/// Throw an ArgumentException if it isn't.
 852		/// </summary>
 853		/// <typeparam name="ExpectedType">Expected type of the parameter
 854		/// </typeparam>
 855		/// <param name="name">parameter name</param>
 856		/// <param name="value">parameter value</param>
 857		private void CheckGenericType<ExpectedType>(string name, object value)
 858		{
 859			if (!(value is ExpectedType))
 860			{
 861				throw new ArgumentException(
 862					"The value " + value + " isn't of type " + typeof(ExpectedType) +
 863					" and can't be used in this generic collection.", name);
 864			}
 865		}
 866		#endregion
 867
 868		#endregion
 869	}
 870
 871	/// <summary>
 872	/// Test dictionary base helper, needs to be an extra class because
 873	/// DictionaryBase is a generic class.
 874	/// </summary>
 875	internal class DictionaryBaseTests
 876	{
 877		#region Helpers
 878
 879		#region TestDictionary
 880		/// <summary>
 881		/// Test dictionary
 882		/// </summary>
 883		private class TestDictionary<TKey, TValue> : DictionaryBase<TKey, TValue>
 884		{
 885			#region Count (Public)
 886			/// <summary>
 887			/// Count
 888			/// </summary>
 889			/// <returns>Int</returns>
 890			public override int Count
 891			{
 892				get
 893				{
 894					return keys.Count;
 895				} // get
 896			}
 897			#endregion
 898
 899			#region Item (Public)
 900			/// <summary>
 901			/// This
 902			/// </summary>
 903			/// <param name="key">Key</param>
 904			/// <returns>TValue</returns>
 905			public override TValue this[TKey key]
 906			{
 907				set
 908				{
 909					int index = keys.IndexOf(key);
 910					if (index < 0)
 911					{
 912						keys.Add(key);
 913						values.Add(value);
 914					}
 915					else
 916					{
 917						values[index] = value;
 918					}
 919				}
 920			}
 921			#endregion
 922
 923			#region Private
 924
 925			#region keys (Private)
 926			/// <summary>
 927			/// Keys
 928			/// </summary>
 929			private readonly List<TKey> keys;
 930			#endregion
 931
 932			#region values (Private)
 933			/// <summary>
 934			/// Values
 935			/// </summary>
 936			private readonly List<TValue> values;
 937			#endregion
 938
 939			#endregion
 940
 941			#region Constructors
 942			/// <summary>
 943			/// Create test dictionary
 944			/// </summary>
 945			/// <param name="keys">Keys</param>
 946			/// <param name="values">Values</param>
 947			public TestDictionary(TKey[] keys, TValue[] values)
 948			{
 949				this.keys = new List<TKey>(keys);
 950				this.values = new List<TValue>(values);
 951			}
 952			#endregion
 953
 954			#region GetEnumerator (Public)
 955			/// <summary>
 956			/// Get enumerator
 957			/// </summary>
 958			/// <returns>IEnumerator</returns>
 959			public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
 960			{
 961				for (int i = 0; i < keys.Count; ++i)
 962				{
 963					yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]);
 964				}
 965			}
 966			#endregion
 967
 968			#region TryGetValue (Public)
 969			/// <summary>
 970			/// Try get value
 971			/// </summary>
 972			/// <param name="key">Key</param>
 973			/// <param name="value">Value</param>
 974			/// <returns>
 975			/// True if getting the value with the key succeeded, false otherwise
 976			/// (the returned value will be the default value, mostly 0 or null).
 977			/// </returns>
 978			public override bool TryGetValue(TKey key, out TValue value)
 979			{
 980				int index = keys.IndexOf(key);
 981				if (index < 0)
 982				{
 983					value = default(TValue);
 984					return false;
 985				}
 986				else
 987				{
 988					value = values[index];
 989					return true;
 990				}
 991			}
 992			#endregion
 993
 994			#region Remove (Public)
 995			/// <summary>
 996			/// Remove value at given key.
 997			/// </summary>
 998			/// <param name="key">Key</param>
 999			/// <returns>
1000			/// True if removing the key and value succeeded, false otherwise.
1001			/// </returns>
1002			public override bool Remove(TKey key)
1003			{
1004				int index = keys.IndexOf(key);
1005				if (index < 0)
1006				{
1007					return false;
1008				}
1009				else
1010				{
1011					keys.RemoveAt(index);
1012					values.RemoveAt(index);
1013					return true;
1014				}
1015			}
1016			#endregion
1017
1018			#region Clear (Public)
1019			/// <summary>
1020			/// Clear
1021			/// </summary>
1022			public override void Clear()
1023			{
1024				keys.Clear();
1025				values.Clear();
1026			}
1027			#endregion
1028		}
1029		#endregion
1030
1031		#endregion
1032
1033		#region TestDictionaryBase (Static)
1034		/// <summary>
1035		/// Test dictionary base. Note: Too slow for a dynamic unit test.
1036		/// </summary>
1037		[Test]
1038		public static void TestDictionaryBase()
1039		{
1040			string[] testKeys = {
1041				"Whats", "up", "inda", "House"
1042			};
1043			int[] testValues = {
1044				10, 2, 51, 20
1045			};
1046
1047			TestDictionary<string, int> testDict =
1048				new TestDictionary<string, int>(testKeys, testValues);
1049
1050			int allValues = 0;
1051			int allDictValues = 0;
1052			for (int num = 0; num < testValues.Length; num++)
1053			{
1054				allValues += testValues[num];
1055			}
1056			foreach (int someValue in testDict.Values)
1057			{
1058				allDictValues += someValue;
1059			}
1060			Assert.Equal(allValues, allDictValues);
1061
1062			Assert.Equal(10, testDict["Whats"]);
1063			Assert.Equal(2, testDict["up"]);
1064			Assert.Equal(51, testDict["inda"]);
1065			Assert.Equal(20, testDict["House"]);
1066		}
1067		#endregion
1068	}
1069}