PageRenderTime 192ms CodeModel.GetById 71ms app.highlight 65ms RepoModel.GetById 45ms app.codeStats 1ms

/Utilities/Collections/MultiDictionaryBase.cs

#
C# | 1336 lines | 737 code | 124 blank | 475 comment | 41 complexity | 1771ac5b4c1693546db31145a7a7fb25 MD5 | raw file
   1using System;
   2using System.Collections.Generic;
   3using System.Diagnostics;
   4using System.Text;
   5using Delta.Utilities.Helpers;
   6
   7namespace Delta.Utilities.Collections
   8{
   9	/// <summary>
  10	/// MultiDictionaryBase is a base class that can be used to more easily
  11	/// implement a class that associates multiple values to a single key.
  12	/// The class implements the generic
  13	/// IDictionary&lt;TKey, ICollection&lt;TValue&gt;&gt; interface.
  14	/// </summary>
  15	/// <remarks>
  16	/// <para>To use MultiDictionaryBase as a base class, the derived class must
  17	/// override Count, Clear, Add, Remove(TKey), Remove(TKey,TValue),
  18	/// Contains(TKey,TValue), EnumerateKeys, and TryEnumerateValuesForKey.
  19	/// </para>
  20	/// <para>It may wish consider overriding CountValues, CountAllValues,
  21	/// ContainsKey, and EqualValues, but these are not required.
  22	/// </para>
  23	/// <para>For unit tests see MultiDictionary class.</para>
  24	/// </remarks>
  25	/// <typeparam name="TKey">Key type</typeparam>
  26	/// <typeparam name="TValue">Value type</typeparam>
  27	[DebuggerDisplay("{DebuggerToString()}")]
  28	public abstract class MultiDictionaryBase<TKey, TValue>
  29		: CollectionBase<KeyValuePair<TKey, ICollection<TValue>>>,
  30		  IDictionary<TKey, ICollection<TValue>>
  31	{
  32		#region ValuesForKeyCollection Class
  33		/// <summary>
  34		/// A private class that provides the ICollection&lt;TValue&gt; for a
  35		/// particular key. This is the collection that is returned from the
  36		/// indexer. The collections is read-write, live, and can be used to add,
  37		/// remove, etc. values from the multi-dictionary.
  38		/// </summary>
  39		private sealed class ValuesForKeyCollection : CollectionBase<TValue>
  40		{
  41			#region Count (Public)
  42			/// <summary>
  43			/// Get the number of values associated with the key.
  44			/// </summary>
  45			public override int Count
  46			{
  47				get
  48				{
  49					return myDictionary.CountValues(key);
  50				}
  51			}
  52			#endregion
  53
  54			#region Private
  55
  56			#region myDictionary (Private)
  57			/// <summary>
  58			/// My dictionary
  59			/// </summary>
  60			private readonly MultiDictionaryBase<TKey, TValue> myDictionary;
  61			#endregion
  62
  63			#region key (Private)
  64			/// <summary>
  65			/// Key
  66			/// </summary>
  67			private readonly TKey key;
  68			#endregion
  69
  70			#endregion
  71
  72			#region Constructors
  73			/// <summary>
  74			/// Constructor. Initializes this collection.
  75			/// </summary>
  76			/// <param name="myDictionary">Dictionary we're using.</param>
  77			/// <param name="key">The key we're looking at.</param>
  78			public ValuesForKeyCollection(
  79				MultiDictionaryBase<TKey, TValue> myDictionary, TKey key)
  80			{
  81				this.myDictionary = myDictionary;
  82				this.key = key;
  83			}
  84			#endregion
  85
  86			#region Clear (Public)
  87			/// <summary>
  88			/// Remove the key and all values associated with it.
  89			/// </summary>
  90			public override void Clear()
  91			{
  92				myDictionary.Remove(key);
  93			}
  94			#endregion
  95
  96			#region Add (Public)
  97			/// <summary>
  98			/// Add a new values to this key.
  99			/// </summary>
 100			/// <param name="item">New values to add.</param>
 101			public override void Add(TValue item)
 102			{
 103				myDictionary.Add(key, item);
 104			}
 105			#endregion
 106
 107			#region Remove (Public)
 108			/// <summary>
 109			/// Remove a value currently associated with key.
 110			/// </summary>
 111			/// <param name="item">Value to remove.</param>
 112			/// <returns>True if item was assocaited with key, false otherwise.
 113			/// </returns>
 114			public override bool Remove(TValue item)
 115			{
 116				return myDictionary.Remove(key, item);
 117			}
 118			#endregion
 119
 120			#region GetEnumerator (Public)
 121			/// <summary>
 122			/// Enumerate all the values associated with key.
 123			/// </summary>
 124			/// <returns>An IEnumerator&lt;TValue&gt; that enumerates all the
 125			/// values associated with key.</returns>
 126			public override IEnumerator<TValue> GetEnumerator()
 127			{
 128				IEnumerator<TValue> values;
 129				if (myDictionary.TryEnumerateValuesForKey(key, out values))
 130				{
 131					return values;
 132				}
 133				else
 134				{
 135					return NoValues();
 136				}
 137			}
 138			#endregion
 139
 140			#region Contains (Public)
 141			/// <summary>
 142			/// Determines if the given values is associated with key.
 143			/// </summary>
 144			/// <param name="item">Value to check for.</param>
 145			/// <returns>True if value is associated with key, false otherwise.
 146			/// </returns>
 147			public override bool Contains(TValue item)
 148			{
 149				return myDictionary.Contains(key, item);
 150			}
 151			#endregion
 152
 153			#region Methods (Private)
 154
 155			#region NoValues
 156			/// <summary>
 157			/// A simple function that returns an IEnumerator&lt;TValue&gt; that
 158			/// doesn't yield any values. A helper.
 159			/// </summary>
 160			/// <returns>An IEnumerator&lt;TValue&gt; that yields no values.
 161			/// </returns>
 162			private IEnumerator<TValue> NoValues()
 163			{
 164				yield break;
 165			}
 166			#endregion
 167
 168			#endregion
 169		}
 170		#endregion
 171
 172		#region KeysCollection Class
 173		/// <summary>
 174		/// A private class that implements ICollection&lt;TKey&gt; and
 175		/// ICollection for the Keys collection. The collection is read-only.
 176		/// </summary>
 177		private sealed class KeysCollection : CollectionBase<TKey>
 178		{
 179			#region Count (Public)
 180			/// <summary>
 181			/// Count
 182			/// </summary>
 183			/// <returns>Int</returns>
 184			public override int Count
 185			{
 186				get
 187				{
 188					return myDictionary.Count;
 189				} // get
 190			}
 191			#endregion
 192
 193			#region Private
 194
 195			#region myDictionary (Private)
 196			/// <summary>
 197			/// My dictionary
 198			/// </summary>
 199			private readonly MultiDictionaryBase<TKey, TValue> myDictionary;
 200			#endregion
 201
 202			#endregion
 203
 204			#region Constructors
 205			/// <summary>
 206			/// Constructor.
 207			/// </summary>
 208			/// <param name="myDictionary">The dictionary this is associated with.
 209			/// </param>
 210			public KeysCollection(MultiDictionaryBase<TKey, TValue> myDictionary)
 211			{
 212				this.myDictionary = myDictionary;
 213			}
 214			#endregion
 215
 216			#region GetEnumerator (Public)
 217			/// <summary>
 218			/// Get enumerator
 219			/// </summary>
 220			/// <returns>IEnumerator</returns>
 221			public override IEnumerator<TKey> GetEnumerator()
 222			{
 223				return myDictionary.EnumerateKeys();
 224			}
 225			#endregion
 226
 227			#region Contains (Public)
 228			/// <summary>
 229			/// Contains
 230			/// </summary>
 231			/// <param name="key">Key</param>
 232			/// <returns>True if the key was found, false otherwise.</returns>
 233			public override bool Contains(TKey key)
 234			{
 235				return myDictionary.ContainsKey(key);
 236			}
 237			#endregion
 238
 239			#region Clear (Public)
 240			/// <summary>
 241			/// Clear
 242			/// </summary>
 243			public override void Clear()
 244			{
 245				throw new Exception("The method or operation is not supported!");
 246			}
 247			#endregion
 248
 249			#region Remove (Public)
 250			/// <summary>
 251			/// Remove. Do not call, this method is not implemented!
 252			/// </summary>
 253			/// <param name="item">Item</param>
 254			/// <returns>True if removing the item succeeded.</returns>
 255			public override bool Remove(TKey item)
 256			{
 257				throw new Exception("The method or operation is not supported!");
 258			}
 259			#endregion
 260		}
 261		#endregion
 262
 263		#region ValuesCollection Class
 264		/// <summary>
 265		/// A private class that implements ICollection&lt;TValue&gt; and
 266		/// ICollection for the Values collection. The collection is read-only.
 267		/// </summary>
 268		private sealed class ValuesCollection : CollectionBase<TValue>
 269		{
 270			#region Count (Public)
 271			/// <summary>
 272			/// Count
 273			/// </summary>
 274			/// <returns>Int</returns>
 275			public override int Count
 276			{
 277				get
 278				{
 279					return myDictionary.CountAllValues();
 280				} // get
 281			}
 282			#endregion
 283
 284			#region Private
 285
 286			#region myDictionary (Private)
 287			/// <summary>
 288			/// My dictionary
 289			/// </summary>
 290			private readonly MultiDictionaryBase<TKey, TValue> myDictionary;
 291			#endregion
 292
 293			#endregion
 294
 295			#region Constructors
 296			/// <summary>
 297			/// Create values collection
 298			/// </summary>
 299			/// <param name="myDictionary">My dictionary</param>
 300			public ValuesCollection(MultiDictionaryBase<TKey, TValue> myDictionary)
 301			{
 302				this.myDictionary = myDictionary;
 303			}
 304			#endregion
 305
 306			#region GetEnumerator (Public)
 307			/// <summary>
 308			/// Get enumerator
 309			/// </summary>
 310			/// <returns>IEnumerator</returns>
 311			public override IEnumerator<TValue> GetEnumerator()
 312			{
 313				using (IEnumerator<TKey> enumKeys = myDictionary.EnumerateKeys())
 314				{
 315					while (enumKeys.MoveNext())
 316					{
 317						TKey key = enumKeys.Current;
 318						IEnumerator<TValue> enumValues;
 319						if (myDictionary.TryEnumerateValuesForKey(key, out enumValues))
 320						{
 321							using (enumValues)
 322							{
 323								while (enumValues.MoveNext())
 324								{
 325									yield return enumValues.Current;
 326								}
 327							}
 328						}
 329					}
 330				}
 331			}
 332			#endregion
 333
 334			#region Contains (Public)
 335			/// <summary>
 336			/// Contains
 337			/// </summary>
 338			/// <param name="value">Value</param>
 339			/// <returns>True if the value was found in the collection.</returns>
 340			public override bool Contains(TValue value)
 341			{
 342				foreach (TValue v in this)
 343				{
 344					if (myDictionary.EqualValues(v, value))
 345					{
 346						return true;
 347					}
 348				}
 349				return false;
 350			}
 351			#endregion
 352
 353			#region Clear (Public)
 354			/// <summary>
 355			/// Clear
 356			/// </summary>
 357			public override void Clear()
 358			{
 359				throw new Exception("The method or operation is not supported!");
 360			}
 361			#endregion
 362
 363			#region Remove (Public)
 364			/// <summary>
 365			/// Remove. Do not call, this method is not implemented!
 366			/// </summary>
 367			/// <param name="value">Value</param>
 368			/// <returns>True if the removal succeeded.</returns>
 369			public override bool Remove(TValue value)
 370			{
 371				throw new Exception("The method or operation is not supported!");
 372			}
 373			#endregion
 374		}
 375		#endregion
 376
 377		#region EnumerableValuesCollection Class
 378		/// <summary>
 379		/// A private class that implements
 380		/// ICollection&lt;ICollection&lt;TValue&gt;&gt; and ICollection for the
 381		/// Values collection on IDictionary. The collection is read-only.
 382		/// </summary>
 383		private sealed class EnumerableValuesCollection
 384			: CollectionBase<ICollection<TValue>>
 385		{
 386			#region Count (Public)
 387			/// <summary>
 388			/// Count
 389			/// </summary>
 390			/// <returns>Int</returns>
 391			public override int Count
 392			{
 393				get
 394				{
 395					return myDictionary.Count;
 396				} // get
 397			}
 398			#endregion
 399
 400			#region Private
 401
 402			#region myDictionary (Private)
 403			/// <summary>
 404			/// My dictionary
 405			/// </summary>
 406			private readonly MultiDictionaryBase<TKey, TValue> myDictionary;
 407			#endregion
 408
 409			#endregion
 410
 411			#region Constructors
 412			/// <summary>
 413			/// Create enumerable values collection
 414			/// </summary>
 415			/// <param name="myDictionary">My dictionary</param>
 416			public EnumerableValuesCollection(
 417				MultiDictionaryBase<TKey, TValue> myDictionary)
 418			{
 419				this.myDictionary = myDictionary;
 420			}
 421			#endregion
 422
 423			#region GetEnumerator (Public)
 424			/// <summary>
 425			/// Get enumerator
 426			/// </summary>
 427			/// <returns>IEnumerator</returns>
 428			public override IEnumerator<ICollection<TValue>> GetEnumerator()
 429			{
 430				using (IEnumerator<TKey> enumKeys = myDictionary.EnumerateKeys())
 431				{
 432					while (enumKeys.MoveNext())
 433					{
 434						TKey key = enumKeys.Current;
 435						yield return new ValuesForKeyCollection(myDictionary, key);
 436					}
 437				}
 438			}
 439			#endregion
 440
 441			#region Contains (Public)
 442			/// <summary>
 443			/// Contains
 444			/// </summary>
 445			/// <param name="values">Values</param>
 446			/// <returns>True if all the values were found.</returns>
 447			public override bool Contains(ICollection<TValue> values)
 448			{
 449				if (values == null)
 450				{
 451					return false;
 452				}
 453				TValue[] valueArray = ArrayHelper.ToArray(values);
 454
 455				foreach (ICollection<TValue> v in this)
 456				{
 457					if (v.Count !=
 458					    valueArray.Length)
 459					{
 460						continue;
 461					}
 462
 463					// First check in order for efficiency.
 464					if (ArrayHelper.AreCollectionsEqual(v, values,
 465						//myDictionary.EqualValues))
 466						myDictionary.valueEqualityComparer))
 467					{
 468						return true;
 469					}
 470
 471					// Now check not in order. We can't use Algorithms.EqualSets, because
 472					// we don't have an IEqualityComparer, just the ability to compare
 473					// for equality. Unfortunately this is N squared, but there isn't a
 474					// good choice here. We don't really expect this method to be used
 475					// much.
 476					bool[] found = new bool[valueArray.Length];
 477					foreach (TValue x in v)
 478					{
 479						for (int i = 0; i < valueArray.Length; ++i)
 480						{
 481							if (!found[i] &&
 482							    myDictionary.EqualValues(x, valueArray[i]))
 483							{
 484								found[i] = true;
 485							}
 486						}
 487					}
 488
 489					// Every item was found. The sets must be equal.
 490					if (Array.IndexOf(found, false) < 0)
 491					{
 492						return true;
 493					}
 494				}
 495				return false;
 496			}
 497			#endregion
 498
 499			#region Clear (Public)
 500			/// <summary>
 501			/// Clear
 502			/// </summary>
 503			public override void Clear()
 504			{
 505				throw new Exception("The method or operation is not supported!");
 506			}
 507			#endregion
 508
 509			#region Remove (Public)
 510			/// <summary>
 511			/// Remove. Do not call, this method is not implemented!
 512			/// </summary>
 513			/// <param name="item">Item</param>
 514			/// <returns>True if the removal succeeded.</returns>
 515			public override bool Remove(ICollection<TValue> item)
 516			{
 517				throw new Exception("The method or operation is not supported!");
 518			}
 519			#endregion
 520		}
 521		#endregion
 522
 523		#region KeyValuePairsCollection Class
 524		/// <summary>
 525		/// A private class that implements
 526		/// ICollection&lt;KeyValuePair&lt;TKey,TValue&gt;&gt; and ICollection
 527		/// for the KeyValuePairs collection. The collection is read-only.
 528		/// </summary>
 529		private sealed class KeyValuePairsCollection
 530			: CollectionBase<KeyValuePair<TKey, TValue>>
 531		{
 532			#region Count (Public)
 533			/// <summary>
 534			/// Count
 535			/// </summary>
 536			/// <returns>Int</returns>
 537			public override int Count
 538			{
 539				get
 540				{
 541					return myDictionary.CountAllValues();
 542				} // get
 543			}
 544			#endregion
 545
 546			#region Private
 547
 548			#region myDictionary (Private)
 549			/// <summary>
 550			/// My dictionary
 551			/// </summary>
 552			private readonly MultiDictionaryBase<TKey, TValue> myDictionary;
 553			#endregion
 554
 555			#endregion
 556
 557			#region Constructors
 558			/// <summary>
 559			/// Create key value pairs collection
 560			/// </summary>
 561			/// <param name="myDictionary">My dictionary</param>
 562			public KeyValuePairsCollection(
 563				MultiDictionaryBase<TKey, TValue> myDictionary)
 564			{
 565				this.myDictionary = myDictionary;
 566			}
 567			#endregion
 568
 569			#region GetEnumerator (Public)
 570			/// <summary>
 571			/// Get enumerator
 572			/// </summary>
 573			/// <returns>IEnumerator</returns>
 574			public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
 575			{
 576				using (IEnumerator<TKey> enumKeys = myDictionary.EnumerateKeys())
 577				{
 578					while (enumKeys.MoveNext())
 579					{
 580						TKey key = enumKeys.Current;
 581						IEnumerator<TValue> enumValues;
 582						if (myDictionary.TryEnumerateValuesForKey(key, out enumValues))
 583						{
 584							using (enumValues)
 585							{
 586								while (enumValues.MoveNext())
 587								{
 588									yield return new KeyValuePair<TKey, TValue>(
 589										key, enumValues.Current);
 590								}
 591							}
 592						}
 593					}
 594				}
 595			}
 596			#endregion
 597
 598			#region Contains (Public)
 599			/// <summary>
 600			/// Contains
 601			/// </summary>
 602			/// <param name="pair">Pair</param>
 603			/// <returns>True if the pair was found, false otherwise.</returns>
 604			public override bool Contains(KeyValuePair<TKey, TValue> pair)
 605			{
 606				return myDictionary[pair.Key].Contains(pair.Value);
 607			}
 608			#endregion
 609
 610			#region Clear (Public)
 611			/// <summary>
 612			/// Clear
 613			/// </summary>
 614			public override void Clear()
 615			{
 616				throw new Exception("The method or operation is not supported!");
 617			}
 618			#endregion
 619
 620			#region Remove (Public)
 621			/// <summary>
 622			/// Remove. Do not call, this method is not implemented!
 623			/// </summary>
 624			/// <param name="item">Item</param>
 625			/// <returns>True if the removal succeeded, false otherwise.</returns>
 626			public override bool Remove(KeyValuePair<TKey, TValue> item)
 627			{
 628				throw new Exception("The method or operation is not supported!");
 629			}
 630			#endregion
 631		}
 632		#endregion
 633
 634		#region Keys (Public)
 635		/// <summary>
 636		/// Gets a read-only collection all the keys in this dictionary.
 637		/// </summary>
 638		/// <value>An readonly ICollection&lt;TKey&gt; of all the keys in this
 639		/// dictionary.</value>
 640		/// <typeparam name="TKey">TKey</typeparam>
 641		/// <typeparam name="TValue">TValue</typeparam>
 642		public virtual ICollection<TKey> Keys
 643		{
 644			get
 645			{
 646				return new KeysCollection(this);
 647			} // get
 648		}
 649		#endregion
 650
 651		#region Values (Public)
 652		/// <summary>
 653		/// Gets a read-only collection of all the values in the dictionary. 
 654		/// </summary>
 655		/// <returns>A read-only ICollection&lt;TValue&gt; of all the values
 656		/// in the dictionary.</returns>
 657		/// <typeparam name="TKey">TKey</typeparam>
 658		/// <typeparam name="TValue">TValue</typeparam>
 659		public virtual ICollection<TValue> Values
 660		{
 661			get
 662			{
 663				return new ValuesCollection(this);
 664			} // get
 665		}
 666		#endregion
 667
 668		#region KeyValuePairs (Public)
 669		/// <summary>
 670		/// Gets a read-only collection of all key-value pairs in the dictionary.
 671		/// If a key has multiple values associated with it, then a key-value
 672		/// pair is present for each value associated with the key.
 673		/// </summary>
 674		/// <typeparam name="TKey">TKey</typeparam>
 675		/// <typeparam name="TValue">TValue</typeparam>
 676		public virtual ICollection<KeyValuePair<TKey, TValue>> KeyValuePairs
 677		{
 678			get
 679			{
 680				return new KeyValuePairsCollection(this);
 681			} // get
 682		}
 683		#endregion
 684
 685		#region Item (Public)
 686		/// <summary>
 687		/// Returns a collection of all of the values in the dictionary associated
 688		/// with <paramref name="key"/>, or changes the set of values associated
 689		/// with <paramref name="key"/>. If the key is not present in the
 690		/// dictionary, an ICollection enumerating no values is returned. The
 691		/// returned collection of values is read-write, and can be used to
 692		/// modify the collection of values associated with the key.
 693		/// </summary>
 694		/// <param name="key">The key to get the values associated with.</param>
 695		/// <value>An ICollection&lt;TValue&gt; with all the values associated
 696		/// with <paramref name="key"/>.</value>
 697		public virtual ICollection<TValue> this[TKey key]
 698		{
 699			get
 700			{
 701				return new ValuesForKeyCollection(this, key);
 702			}
 703			set
 704			{
 705				ReplaceMany(key, value);
 706			}
 707		}
 708		#endregion
 709
 710		#region Count (Public)
 711		/// <summary>
 712		/// Gets the number of keys in the dictionary.
 713		/// This property must be overridden in the derived class.
 714		/// </summary>
 715		/// <typeparam name="TKey">TKey</typeparam>
 716		/// <typeparam name="TValue">TValue</typeparam>
 717		public abstract override int Count
 718		{
 719			get;
 720		}
 721		#endregion
 722
 723		#region Private
 724
 725		#region Item (Private)
 726		/// <summary>
 727		/// Gets a collection of all the values in the dictionary associated with
 728		/// <paramref name="key"/>, or changes the set of values associated with
 729		/// <paramref name="key"/>. If the key is not present in the dictionary,
 730		/// a KeyNotFound exception is thrown.
 731		/// </summary>
 732		/// <param name="key">The key to get the values associated with.</param>
 733		/// <value>An IEnumerable&lt;TValue&gt; that enumerates all the values
 734		/// associated with <paramref name="key"/>.</value>
 735		/// <exception cref="KeyNotFoundException">The given key is not present
 736		/// in the dictionary.</exception>
 737		ICollection<TValue> IDictionary<TKey, ICollection<TValue>>.this[TKey key]
 738		{
 739			get
 740			{
 741				if (ContainsKey(key))
 742				{
 743					return new ValuesForKeyCollection(this, key);
 744				}
 745				else
 746				{
 747					throw new KeyNotFoundException(
 748						"The key was not found in the collection.");
 749				}
 750			}
 751			set
 752			{
 753				ReplaceMany(key, value);
 754			}
 755		}
 756		#endregion
 757
 758		#region Values (Private)
 759		/// <summary>
 760		/// Gets a read-only collection of all the value collections in the
 761		/// dictionary. 
 762		/// </summary>
 763		/// <returns>A read-only ICollection&lt;IEnumerable&lt;TValue&gt;&gt;
 764		/// of all the values in the dictionary.</returns>
 765		ICollection<ICollection<TValue>>
 766			IDictionary<TKey, ICollection<TValue>>.Values
 767		{
 768			get
 769			{
 770				return new EnumerableValuesCollection(this);
 771			} // get
 772		}
 773		#endregion
 774
 775		#region valueEqualityComparer (Private)
 776		/// <summary>
 777		/// Cache the equality comparer after we get it the first time.
 778		/// </summary>
 779		/// <typeparam name="TKey">TKey</typeparam>
 780		/// <typeparam name="TValue">TValue</typeparam>
 781		private volatile IEqualityComparer<TValue> valueEqualityComparer;
 782		#endregion
 783
 784		#endregion
 785
 786		#region ICollection<KeyValuePair<TKey,ICollection<TValue>>> Members
 787		/// <summary>
 788		/// Adds a key-value pair to the collection. The value part of the pair
 789		/// must be a collection of values to associate with the key. If values
 790		/// are already associated with the given key, the new values are added
 791		/// to the ones associated with that key.
 792		/// </summary>
 793		/// <param name="item">A KeyValuePair contains the Key and Value
 794		/// collection to add.</param>
 795		public override void Add(KeyValuePair<TKey, ICollection<TValue>> item)
 796		{
 797			AddMany(item.Key, item.Value);
 798		}
 799
 800		/// <summary>
 801		/// Clears the dictionary.
 802		/// This method must be overridden in the derived class.
 803		/// </summary>
 804		public abstract override void Clear();
 805
 806		/// <summary>
 807		/// Determines if this dictionary contains the given key and all of the
 808		/// values associated with that key..
 809		/// </summary>
 810		/// <param name="item">A key and collection of values to search for.
 811		/// </param>
 812		/// <returns>True if the dictionary has associated all of the values in
 813		/// <paramref name="item"/>.Value with <paramref name="item"/>.Key.
 814		/// </returns>
 815		public override bool Contains(KeyValuePair<TKey, ICollection<TValue>> item)
 816		{
 817			foreach (TValue val in item.Value)
 818			{
 819				if (!Contains(item.Key, val))
 820				{
 821					return false;
 822				}
 823			}
 824
 825			return true;
 826		}
 827
 828		/// <summary>
 829		/// Removes a set of values from a given key. If all values associated
 830		/// with a key are removed, then the key is removed also.
 831		/// </summary>
 832		/// <param name="item">A KeyValuePair contains a key and a set of values
 833		/// to remove from that key.</param>
 834		/// <returns>True if at least one values was found and removed.</returns>
 835		public override bool Remove(KeyValuePair<TKey, ICollection<TValue>> item)
 836		{
 837			return RemoveMany(item.Key, item.Value) > 0;
 838		}
 839		#endregion
 840
 841		#region IDictionary<TKey,ICollection<TValue>> Members
 842		/// <summary>
 843		/// Determines whether a given key is found in the dictionary.
 844		/// </summary>
 845		/// <remarks>The default implementation simply calls
 846		/// TryEnumerateValuesForKey. It may be appropriate to override this
 847		/// method to provide a more efficient implementation.</remarks>
 848		/// <param name="key">Key to look for in the dictionary.</param>
 849		/// <returns>True if the key is present in the dictionary.</returns>
 850		public virtual bool ContainsKey(TKey key)
 851		{
 852			IEnumerator<TValue> values;
 853			return TryEnumerateValuesForKey(key, out values);
 854		}
 855
 856		/// <summary>
 857		/// Removes a key from the dictionary.
 858		/// This method must be overridden in the derived class.
 859		/// </summary>
 860		/// <param name="key">Key to remove from the dictionary.</param>
 861		/// <returns>True if the key was found, false otherwise.</returns>
 862		public abstract bool Remove(TKey key);
 863
 864		/// <summary>
 865		/// Implements IDictionary&lt;TKey, IEnumerable&lt;TValue&gt;&gt;.Add.
 866		/// If the key is already present, and ArgumentException is thrown.
 867		/// Otherwise, a new key is added, and new values are associated with
 868		/// that key.
 869		/// </summary>
 870		/// <param name="key">Key to add.</param>
 871		/// <param name="values">Values to associate with that key.</param>
 872		/// <exception cref="ArgumentException">The key is already present in the
 873		/// dictionary.</exception>
 874		void IDictionary<TKey, ICollection<TValue>>.Add(
 875			TKey key, ICollection<TValue> values)
 876		{
 877			if (ContainsKey(key))
 878			{
 879				throw new ArgumentException(
 880					"The key was already present in the dictionary.", "key");
 881			}
 882			else
 883			{
 884				AddMany(key, values);
 885			}
 886		}
 887
 888		/// <summary>
 889		/// Determines if this dictionary contains a key equal to
 890		/// <paramref name="key"/>. If so, all the values associated with that key
 891		/// are returned through the values parameter. This method must be
 892		/// overridden by the derived class.
 893		/// </summary>
 894		/// <param name="key">The key to search for.</param>
 895		/// <param name="values">Returns all values associated with key, if true
 896		/// was returned.</param>
 897		/// <returns>True if the dictionary contains key. False if the dictionary
 898		/// does not contain key.</returns>
 899		bool IDictionary<TKey, ICollection<TValue>>.TryGetValue(
 900			TKey key, out ICollection<TValue> values)
 901		{
 902			if (ContainsKey(key))
 903			{
 904				values = this[key];
 905				return true;
 906			}
 907			else
 908			{
 909				values = null;
 910				return false;
 911			}
 912		}
 913		#endregion
 914
 915		#region IEnumerable<KeyValuePair<TKey,ICollection<TValue>>> Members
 916		/// <summary>
 917		/// Enumerate all the keys in the dictionary, and for each key, the
 918		/// collection of values for that key.
 919		/// </summary>
 920		/// <returns>An enumerator to enumerate all the key,
 921		/// ICollection&lt;value&gt; pairs in the dictionary.</returns>
 922		public override IEnumerator<KeyValuePair<TKey, ICollection<TValue>>>
 923			GetEnumerator()
 924		{
 925			using (IEnumerator<TKey> enumKeys = EnumerateKeys())
 926			{
 927				while (enumKeys.MoveNext())
 928				{
 929					TKey key = enumKeys.Current;
 930					yield return new KeyValuePair<TKey, ICollection<TValue>>(
 931						key, new ValuesForKeyCollection(this, key));
 932				}
 933			}
 934		}
 935		#endregion
 936
 937		#region Add (Public)
 938		/// <summary>
 939		/// Adds a new key-value pair to the dictionary.
 940		/// This method must be overridden in the derived class.
 941		/// </summary>
 942		/// <param name="key">Key to add.</param>
 943		/// <param name="value">Value to associated with the key.</param>
 944		/// <exception cref="ArgumentException">key is already present in the
 945		/// dictionary</exception>
 946		public abstract void Add(TKey key, TValue value);
 947		#endregion
 948
 949		#region Remove (Public)
 950		/// <summary>
 951		/// Removes a key-value pair from the dictionary.
 952		/// This method must be overridden in the derived class.
 953		/// </summary>
 954		/// <param name="key">Key to remove from the dictionary.</param>
 955		/// <param name="value">Associated value to remove from the dictionary.</param>
 956		/// <returns>True if the key-value pair was found, false otherwise.</returns>
 957		public abstract bool Remove(TKey key, TValue value);
 958		#endregion
 959
 960		#region AddMany (Public)
 961		/// <summary>
 962		/// <para>Adds new values to be associated with a key. If duplicate values
 963		/// are permitted, this method always adds new key-value pairs to the
 964		/// dictionary.</para>
 965		/// <para>If duplicate values are not permitted, and <paramref name="key"/>
 966		/// already has a value equal to one of <paramref name="values"/>
 967		/// associated with it, then that value is replaced, and the number of
 968		/// values associate with <paramref name="key"/> is unchanged.</para>
 969		/// </summary>
 970		/// <param name="key">The key to associate with.</param>
 971		/// <param name="values">A collection of values to associate with
 972		/// <paramref name="key"/>.</param>
 973		public virtual void AddMany(TKey key, IEnumerable<TValue> values)
 974		{
 975			foreach (TValue value in values)
 976			{
 977				Add(key, value);
 978			}
 979		}
 980		#endregion
 981
 982		#region RemoveMany (Public)
 983		/// <summary>
 984		/// Removes a collection of values from the values associated with a key.
 985		/// If the last value is removed from a key, the key is removed also.
 986		/// </summary>
 987		/// <param name="key">A key to remove values from.</param>
 988		/// <param name="values">A collection of values to remove.</param>
 989		/// <returns>The number of values that were present and removed. </returns>
 990		public virtual int RemoveMany(TKey key, IEnumerable<TValue> values)
 991		{
 992			int countRemoved = 0;
 993
 994			foreach (TValue val in values)
 995			{
 996				if (Remove(key, val))
 997				{
 998					++countRemoved;
 999				}
1000			}
1001
1002			return countRemoved;
1003		}
1004
1005		/// <summary>
1006		/// Remove all of the keys (and any associated values) in a collection
1007		/// of keys. If a key is not present in the dictionary, nothing happens.
1008		/// </summary>
1009		/// <param name="keyCollection">A collection of key values to remove.
1010		/// </param>
1011		/// <returns>The number of keys from the collection that were present and
1012		/// removed.</returns>
1013		public int RemoveMany(IEnumerable<TKey> keyCollection)
1014		{
1015			int count = 0;
1016			foreach (TKey key in keyCollection)
1017			{
1018				if (Remove(key))
1019				{
1020					++count;
1021				}
1022			}
1023
1024			return count;
1025		}
1026		#endregion
1027
1028		#region Contains (Public)
1029		/// <summary>
1030		/// Determines if this dictionary contains a key-value pair equal to
1031		/// <paramref name="key"/> and <paramref name="value"/>. The dictionary
1032		/// is not changed. This method must be overridden in the derived class.
1033		/// </summary>
1034		/// <param name="key">The key to search for.</param>
1035		/// <param name="value">The value to search for.</param>
1036		/// <returns>True if the dictionary has associated <paramref name="value"/>
1037		/// with <paramref name="key"/>.</returns>
1038		public abstract bool Contains(TKey key, TValue value);
1039		#endregion
1040
1041		#region Replace (Public)
1042		/// <summary>
1043		/// Replaces all values associated with <paramref name="key"/> with the
1044		/// single value <paramref name="value"/>.
1045		/// </summary>
1046		/// <remarks>This implementation simply calls Remove, followed by Add.
1047		/// </remarks>
1048		/// <param name="key">The key to associate with.</param>
1049		/// <param name="value">The new values to be associated with
1050		/// <paramref name="key"/>.</param>
1051		/// <returns>Returns true if some values were removed. Returns false if
1052		/// <paramref name="key"/> was not present in the dictionary before Replace
1053		/// was called.</returns>
1054		public virtual bool Replace(TKey key, TValue value)
1055		{
1056			bool removed = Remove(key);
1057			Add(key, value);
1058			return removed;
1059		}
1060		#endregion
1061
1062		#region ReplaceMany (Public)
1063		/// <summary>
1064		/// Replaces all values associated with <paramref name="key"/> with a new
1065		/// collection of values. If the collection does not permit duplicate
1066		/// values, and <paramref name="values"/> has duplicate items, then only
1067		/// the last of duplicates is added.
1068		/// </summary>
1069		/// <param name="key">The key to associate with.</param>
1070		/// <param name="values">The new values to be associated with
1071		/// <paramref name="key"/>.</param>
1072		/// <returns>Returns true if some values were removed. Returns false if
1073		/// <paramref name="key"/> was not
1074		/// present in the dictionary before Replace was called.</returns>
1075		public bool ReplaceMany(TKey key, IEnumerable<TValue> values)
1076		{
1077			bool removed = Remove(key);
1078			AddMany(key, values);
1079			return removed;
1080		}
1081		#endregion
1082
1083		#region ToString (Public)
1084		/// <summary>
1085		/// Shows the string representation of the dictionary. The string
1086		/// representation contains a list of the mappings in the dictionary.
1087		/// </summary>
1088		/// <returns>The string representation of the dictionary.</returns>
1089		public override string ToString()
1090		{
1091			bool firstItem = true;
1092
1093			StringBuilder builder = new StringBuilder();
1094
1095			builder.Append("{");
1096
1097			// Call ToString on each item and put it in.
1098			foreach (KeyValuePair<TKey, ICollection<TValue>> pair in this)
1099			{
1100				if (!firstItem)
1101				{
1102					builder.Append(", ");
1103				}
1104
1105				if (pair.Key == null)
1106				{
1107					builder.Append("null");
1108				}
1109				else
1110				{
1111					builder.Append(pair.Key.ToString());
1112				}
1113
1114				builder.Append("->");
1115
1116				// Put all values in a parenthesized list.
1117				builder.Append('(');
1118
1119				bool firstValue = true;
1120				foreach (TValue val in pair.Value)
1121				{
1122					if (!firstValue)
1123					{
1124						builder.Append(",");
1125					}
1126
1127					if (val == null)
1128					{
1129						builder.Append("null");
1130					}
1131					else
1132					{
1133						builder.Append(val.ToString());
1134					}
1135
1136					firstValue = false;
1137				}
1138
1139				builder.Append(')');
1140
1141				firstItem = false;
1142			}
1143
1144			builder.Append("}");
1145			return builder.ToString();
1146		}
1147		#endregion
1148
1149		#region Methods (Private)
1150
1151		#region EnumerateKeys
1152		/// <summary>
1153		/// Enumerate all the keys in the dictionary.
1154		/// This method must be overridden by a derived class.
1155		/// </summary>
1156		/// <returns>An IEnumerator&lt;TKey&gt; that enumerates all of the keys
1157		/// in the collection that have at least one value associated with them.
1158		/// </returns>
1159		protected abstract IEnumerator<TKey> EnumerateKeys();
1160		#endregion
1161
1162		#region TryEnumerateValuesForKey
1163		/// <summary>
1164		/// Enumerate all of the values associated with a given key. This method
1165		/// must be overridden by the derived class. If the key exists and has
1166		/// values associated with it, an enumerator for those values is returned
1167		/// throught <paramref name="values"/>. If the key does not exist, false
1168		/// is returned.
1169		/// </summary>
1170		/// <param name="key">The key to get values for.</param>
1171		/// <param name="values">If true is returned, this parameter receives an
1172		/// enumerators that enumerates the values associated with that key.
1173		/// </param>
1174		/// <returns>True if the key exists and has values associated with it.
1175		/// False otherwise.</returns>
1176		protected abstract bool TryEnumerateValuesForKey(
1177			TKey key, out IEnumerator<TValue> values);
1178		#endregion
1179
1180		#region EqualValues
1181		/// <summary>
1182		/// If the derived class does not use the default comparison for values,
1183		/// this methods should be overridden to compare two values for equality.
1184		/// This is used for the correct implementation of ICollection.Contains
1185		/// on the Values and KeyValuePairs collections.
1186		/// </summary>
1187		/// <param name="value1">First value to compare.</param>
1188		/// <param name="value2">Second value to compare.</param>
1189		/// <returns>True if the values are equal.</returns>
1190		protected virtual bool EqualValues(TValue value1, TValue value2)
1191		{
1192			if (valueEqualityComparer == null)
1193			{
1194				valueEqualityComparer = EqualityComparer<TValue>.Default;
1195			}
1196			return valueEqualityComparer.Equals(value1, value2);
1197		}
1198		#endregion
1199
1200		#region CountValues
1201		/// <summary>
1202		/// Gets a count of the number of values associated with a key. The
1203		/// default implementation is slow; it enumerators all of the values
1204		/// (using TryEnumerateValuesForKey) to count them. A derived class
1205		/// may be able to supply a more efficient implementation.
1206		/// </summary>
1207		/// <param name="key">The key to count values for.</param>
1208		/// <returns>The number of values associated with
1209		/// <paramref name="key"/>.</returns>
1210		protected virtual int CountValues(TKey key)
1211		{
1212			int count = 0;
1213			IEnumerator<TValue> enumValues;
1214
1215			if (TryEnumerateValuesForKey(key, out enumValues))
1216			{
1217				using (enumValues)
1218				{
1219					while (enumValues.MoveNext())
1220					{
1221						count += 1;
1222					}
1223				}
1224			}
1225
1226			return count;
1227		}
1228		#endregion
1229
1230		#region CountAllValues
1231		/// <summary>
1232		/// Gets a total count of values in the collection. This default
1233		/// implementation is slow; it enumerates all of the keys in the dictionary
1234		/// and calls CountValues on each. A derived class may be able to supply
1235		/// a more efficient implementation.
1236		/// </summary>
1237		/// <returns>The total number of values associated with all keys in the
1238		/// dictionary.</returns>
1239		protected virtual int CountAllValues()
1240		{
1241			int count = 0;
1242
1243			using (IEnumerator<TKey> enumKeys = EnumerateKeys())
1244			{
1245				while (enumKeys.MoveNext())
1246				{
1247					TKey key = enumKeys.Current;
1248					count += CountValues(key);
1249				}
1250			}
1251
1252			return count;
1253		}
1254		#endregion
1255
1256		#region DebuggerToString
1257		/// <summary>
1258		/// Display the contents of the dictionary in the debugger. This is
1259		/// intentionally private, it is called only from the debugger due to the
1260		/// presence of the DebuggerDisplay attribute. It is similar format to
1261		/// ToString(), but is limited to 250-300 characters or so, so as not to
1262		/// overload the debugger.
1263		/// </summary>
1264		/// <returns>The string representation of the items in the collection,
1265		/// similar in format to ToString().</returns>
1266		internal new string DebuggerToString()
1267		{
1268			const int MAXLENGTH = 250;
1269
1270			bool firstItem = true;
1271
1272			StringBuilder builder = new StringBuilder();
1273
1274			builder.Append("{");
1275
1276			// Call ToString on each item and put it in.
1277			foreach (KeyValuePair<TKey, ICollection<TValue>> pair in this)
1278			{
1279				if (builder.Length >= MAXLENGTH)
1280				{
1281					builder.Append(", ...");
1282					break;
1283				}
1284
1285				if (!firstItem)
1286				{
1287					builder.Append(", ");
1288				}
1289
1290				if (pair.Key == null)
1291				{
1292					builder.Append("null");
1293				}
1294				else
1295				{
1296					builder.Append(pair.Key.ToString());
1297				}
1298
1299				builder.Append("->");
1300
1301				// Put all values in a parenthesized list.
1302				builder.Append('(');
1303
1304				bool firstValue = true;
1305				foreach (TValue val in pair.Value)
1306				{
1307					if (!firstValue)
1308					{
1309						builder.Append(",");
1310					}
1311
1312					if (val == null)
1313					{
1314						builder.Append("null");
1315					}
1316					else
1317					{
1318						builder.Append(val.ToString());
1319					}
1320
1321					firstValue = false;
1322				}
1323
1324				builder.Append(')');
1325
1326				firstItem = false;
1327			}
1328
1329			builder.Append("}");
1330			return builder.ToString();
1331		}
1332		#endregion
1333
1334		#endregion
1335	}
1336}