diff --git a/Nuclex.Support (Xbox 360).csproj b/Nuclex.Support (Xbox 360).csproj
index 5a01525..d71fd52 100644
--- a/Nuclex.Support (Xbox 360).csproj
+++ b/Nuclex.Support (Xbox 360).csproj
@@ -77,6 +77,10 @@
ObservableCollection.cs
+
+
+ ObservableDictionary.cs
+
PairPriorityQueue.cs
diff --git a/Nuclex.Support.csproj b/Nuclex.Support.csproj
index 0507dd1..704f9b3 100644
--- a/Nuclex.Support.csproj
+++ b/Nuclex.Support.csproj
@@ -59,6 +59,10 @@
ObservableCollection.cs
+
+
+ ObservableDictionary.cs
+
PairPriorityQueue.cs
diff --git a/Source/Collections/ObservableCollection.Test.cs b/Source/Collections/ObservableCollection.Test.cs
index a008f47..cd539cd 100644
--- a/Source/Collections/ObservableCollection.Test.cs
+++ b/Source/Collections/ObservableCollection.Test.cs
@@ -34,23 +34,23 @@ namespace Nuclex.Support.Collections {
#region interface IObservableCollectionSubscriber
- /// Interface used to test the observable collection.
+ /// Interface used to test the observable collection
public interface IObservableCollectionSubscriber {
/// Called when the collection is about to clear its contents
/// Collection that is clearing its contents
- /// Not used
- void Clearing(object sender, EventArgs e);
+ /// Not used
+ void Clearing(object sender, EventArgs arguments);
/// Called when an item is added to the collection
/// Collection to which an item is being added
- /// Contains the item that is being added
- void ItemAdded(object sender, ItemEventArgs e);
+ /// Contains the item that is being added
+ void ItemAdded(object sender, ItemEventArgs arguments);
/// Called when an item is removed from the collection
/// Collection from which an item is being removed
- /// Contains the item that is being removed
- void ItemRemoved(object sender, ItemEventArgs e);
+ /// Contains the item that is being removed
+ void ItemRemoved(object sender, ItemEventArgs arguments);
}
@@ -73,8 +73,6 @@ namespace Nuclex.Support.Collections {
new EventHandler>(
this.mockedSubscriber.ItemRemoved
);
-
- this.mockery.VerifyAllExpectationsHaveBeenMet();
}
/// Tests whether the Clearing event is fired
diff --git a/Source/Collections/ObservableDictionary.Test.cs b/Source/Collections/ObservableDictionary.Test.cs
new file mode 100644
index 0000000..6b932f6
--- /dev/null
+++ b/Source/Collections/ObservableDictionary.Test.cs
@@ -0,0 +1,539 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2009 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+#if UNITTEST
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
+
+using NUnit.Framework;
+using NMock2;
+
+namespace Nuclex.Support.Collections {
+
+ /// Unit Test for the observable dictionary wrapper
+ [TestFixture]
+ public class ObservableDictionaryTest {
+
+ #region interface IObservableDictionarySubscriber
+
+ /// Interface used to test the observable dictionary
+ public interface IObservableDictionarySubscriber {
+
+ /// Called when the dictionary is about to clear its contents
+ /// Dictionary that is clearing its contents
+ /// Not used
+ void Clearing(object sender, EventArgs arguments);
+
+ /// Called when an item is added to the dictionary
+ /// Dictionary to which an item is being added
+ /// Contains the item that is being added
+ void ItemAdded(object sender, ItemEventArgs> arguments);
+
+ /// Called when an item is removed from the dictionary
+ /// Dictionary from which an item is being removed
+ /// Contains the item that is being removed
+ void ItemRemoved(object sender, ItemEventArgs> arguments);
+
+ }
+
+ #endregion // interface IObservableDictionarySubscriber
+
+ /// Initialization routine executed before each test is run
+ [SetUp]
+ public void Setup() {
+ this.mockery = new Mockery();
+
+ this.mockedSubscriber = this.mockery.NewMock();
+
+ this.observedDictionary = new ObservableDictionary();
+ this.observedDictionary.Add(1, "one");
+ this.observedDictionary.Add(2, "two");
+ this.observedDictionary.Add(3, "three");
+ this.observedDictionary.Add(42, "forty-two");
+
+ this.observedDictionary.Clearing += new EventHandler(this.mockedSubscriber.Clearing);
+ this.observedDictionary.ItemAdded +=
+ new EventHandler>>(
+ this.mockedSubscriber.ItemAdded
+ );
+ this.observedDictionary.ItemRemoved +=
+ new EventHandler>>(
+ this.mockedSubscriber.ItemRemoved
+ );
+ }
+
+ ///
+ /// Verifies that the default constructor of the observable dictionary works
+ ///
+ [Test]
+ public void TestDefaultConstructor() {
+ ObservableDictionary testDictionary =
+ new ObservableDictionary();
+
+ Assert.AreEqual(0, testDictionary.Count);
+ }
+
+ ///
+ /// Verifies that the copy constructor of the observable dictionary works
+ ///
+ [Test]
+ public void TestCopyConstructor() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ CollectionAssert.AreEqual(numbers, testDictionary);
+ }
+
+ /// Verifies that the IsReadOnly property is working
+ [Test]
+ public void TestIsReadOnly() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ Assert.IsFalse(testDictionary.IsReadOnly);
+ }
+
+ ///
+ /// Checks whether the Contains() method of the observable dictionary is able to
+ /// determine if the dictionary contains an item
+ ///
+ [Test]
+ public void TestContains() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ Assert.IsTrue(
+ testDictionary.Contains(new KeyValuePair(42, "forty-two"))
+ );
+ Assert.IsFalse(
+ testDictionary.Contains(new KeyValuePair(24, "twenty-four"))
+ );
+ }
+
+ ///
+ /// Checks whether the Contains() method of the observable dictionary is able to
+ /// determine if the dictionary contains a key
+ ///
+ [Test]
+ public void TestContainsKey() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ Assert.IsTrue(testDictionary.ContainsKey(42));
+ Assert.IsFalse(testDictionary.ContainsKey(24));
+ }
+
+ ///
+ /// Verifies that the CopyTo() of the observable dictionary works
+ ///
+ [Test]
+ public void TestCopyToArray() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ KeyValuePair[] items = new KeyValuePair[numbers.Count];
+
+ testDictionary.CopyTo(items, 0);
+
+ CollectionAssert.AreEqual(numbers, items);
+ }
+
+ ///
+ /// Tests whether the typesafe enumerator of the observable dictionary is working
+ ///
+ [Test]
+ public void TestTypesafeEnumerator() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ List> outputItems = new List>();
+ foreach(KeyValuePair item in testDictionary) {
+ outputItems.Add(item);
+ }
+
+ CollectionAssert.AreEqual(numbers, outputItems);
+ }
+
+ ///
+ /// Tests whether the keys collection of the observable dictionary can be queried
+ ///
+ [Test]
+ public void TestGetKeysCollection() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ ICollection inputKeys = numbers.Keys;
+ ICollection keys = testDictionary.Keys;
+ CollectionAssert.AreEquivalent(inputKeys, keys);
+ }
+
+ ///
+ /// Tests whether the values collection of the observable dictionary can be queried
+ ///
+ [Test]
+ public void TestGetValuesCollection() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ ICollection inputValues = numbers.Values;
+ ICollection values = testDictionary.Values;
+ CollectionAssert.AreEquivalent(inputValues, values);
+ }
+
+ ///
+ /// Tests whether the TryGetValue() method of the observable dictionary is working
+ ///
+ [Test]
+ public void TestTryGetValue() {
+ string value;
+
+ Assert.IsTrue(this.observedDictionary.TryGetValue(42, out value));
+ Assert.AreEqual("forty-two", value);
+
+ Assert.IsFalse(this.observedDictionary.TryGetValue(24, out value));
+ Assert.AreEqual(null, value);
+ }
+
+ ///
+ /// Tests whether the retrieval of values using the indexer of the observable
+ /// dictionary is working
+ ///
+ [Test]
+ public void TestRetrieveValueByIndexer() {
+ Assert.AreEqual("forty-two", this.observedDictionary[42]);
+ }
+
+ ///
+ /// Tests whether an exception is thrown if the indexer of the observable dictionary
+ /// is used to attempt to retrieve a non-existing value
+ ///
+ [Test, ExpectedException(typeof(KeyNotFoundException))]
+ public void TestThrowOnRetrieveNonExistingValueByIndexer() {
+ string numberName = this.observedDictionary[24];
+ Console.WriteLine(numberName);
+ }
+
+ ///
+ /// Checks whether the Add() methods works via the generic
+ /// IDictionary<> interface
+ ///
+ [Test]
+ public void TestAddViaGenericIDictionary() {
+ Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
+ (this.observedDictionary as IDictionary).Add(10, "ten");
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ CollectionAssert.Contains(
+ this.observedDictionary, new KeyValuePair(10, "ten")
+ );
+ }
+
+ ///
+ /// Checks whether the Remove() method works via the generic
+ /// IDictionary<> interface
+ ///
+ [Test]
+ public void TestRemoveViaGenericIDictionary() {
+ Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
+ (this.observedDictionary as IDictionary).Remove(3);
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ CollectionAssert.DoesNotContain(this.observedDictionary.Keys, 3);
+ }
+
+ ///
+ /// Tests whether the TryGetValue() method of the observable dictionary is working
+ ///
+ [Test]
+ public void TestRetrieveValueByIndexerViaGenericIDictionary() {
+ Assert.AreEqual(
+ "forty-two", (this.observedDictionary as IDictionary)[42]
+ );
+ }
+
+ ///
+ /// Verifies that the indexer can be used to insert an item via the generic
+ /// IDictionar<> interface
+ ///
+ [Test]
+ public void TestReplaceByIndexerViaGenericIDictionary() {
+ Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
+ Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
+ (this.observedDictionary as IDictionary)[42] = "two and fourty";
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ Assert.AreEqual("two and fourty", this.observedDictionary[42]);
+ }
+
+ ///
+ /// Checks whether the Clear() method of observable dictionary is working
+ ///
+ [Test]
+ public void TestClearViaIDictionary() {
+ Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments();
+ (this.observedDictionary as IDictionary).Clear();
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ Assert.AreEqual(0, this.observedDictionary.Count);
+ }
+
+ ///
+ /// Checks whether the Add() method works via the IDictionary interface
+ ///
+ [Test]
+ public void TestAddViaIDictionary() {
+ Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
+ (this.observedDictionary as IDictionary).Add(24, "twenty-four");
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ CollectionAssert.Contains(
+ this.observedDictionary, new KeyValuePair(24, "twenty-four")
+ );
+ }
+
+ ///
+ /// Checks whether the Contains() method of the observable dictionary is able to
+ /// determine if the dictionary contains an item via the IDictionary interface
+ ///
+ [Test]
+ public void TestContainsViaIDictionary() {
+ Assert.IsTrue((this.observedDictionary as IDictionary).Contains(42));
+ Assert.IsFalse((this.observedDictionary as IDictionary).Contains(24));
+ }
+
+ ///
+ /// Checks whether the GetEnumerator() method of the observable dictionary
+ /// returns a working enumerator if accessed via the IDictionary interface
+ ///
+ [Test]
+ public void TestEnumeratorViaIDictionary() {
+ Dictionary outputNumbers = new Dictionary();
+ foreach(DictionaryEntry entry in (this.observedDictionary as IDictionary)) {
+ (outputNumbers as IDictionary).Add(entry.Key, entry.Value);
+ }
+
+ CollectionAssert.AreEquivalent(this.observedDictionary, outputNumbers);
+ }
+
+ ///
+ /// Checks whether the IsFixedSize property of the observable dictionary returns
+ /// the expected result for a read only dictionary based on a dynamic dictionary
+ ///
+ [Test]
+ public void TestIsFixedSizeViaIList() {
+ Assert.IsFalse((this.observedDictionary as IDictionary).IsFixedSize);
+ }
+
+ ///
+ /// Tests whether the keys collection of the observable dictionary can be queried
+ /// via the IDictionary interface
+ ///
+ [Test]
+ public void TestGetKeysCollectionViaIDictionary() {
+ ICollection keys = (this.observedDictionary as IDictionary).Keys;
+ Assert.AreEqual(this.observedDictionary.Count, keys.Count);
+ }
+
+ ///
+ /// Tests whether the values collection of the observable dictionary can be queried
+ /// via the IDictionary interface
+ ///
+ [Test]
+ public void TestGetValuesCollectionViaIDictionary() {
+ ICollection values = (this.observedDictionary as IDictionary).Values;
+ Assert.AreEqual(this.observedDictionary.Count, values.Count);
+ }
+
+ ///
+ /// Checks whether Remove() method works via the IDictionary interface
+ ///
+ [Test]
+ public void TestRemoveViaIDictionary() {
+ Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
+ (this.observedDictionary as IDictionary).Remove(3);
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ CollectionAssert.DoesNotContain(this.observedDictionary.Keys, 3);
+ }
+
+ ///
+ /// Tests whether the retrieval of values using the indexer of the observable
+ /// dictionary is working via the IDictionary interface
+ ///
+ [Test]
+ public void TestRetrieveValueByIndexerViaIDictionary() {
+ Assert.AreEqual("forty-two", (this.observedDictionary as IDictionary)[42]);
+ }
+
+ ///
+ /// Verifies the indexer can be used to insert an item via the IDictionary interface
+ ///
+ [Test]
+ public void TestReplaceByIndexerViaIDictionary() {
+ Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
+ Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
+ (this.observedDictionary as IDictionary)[42] = "two and fourty";
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ Assert.AreEqual("two and fourty", this.observedDictionary[42]);
+ }
+
+ ///
+ /// Checks whether Add() method is working via the generic
+ /// ICollection<> interface
+ ///
+ [Test]
+ public void TestAddViaGenericICollection() {
+ Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
+ (this.observedDictionary as ICollection>).Add(
+ new KeyValuePair(24, "twenty-four")
+ );
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ CollectionAssert.Contains(
+ this.observedDictionary, new KeyValuePair(24, "twenty-four")
+ );
+ }
+
+ ///
+ /// Checks whether the Clear() method is working via the generic
+ /// ICollection<> interface
+ ///
+ [Test]
+ public void TestClearViaGenericICollection() {
+ Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments();
+ (this.observedDictionary as ICollection>).Clear();
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ Assert.AreEqual(0, this.observedDictionary.Count);
+ }
+
+ ///
+ /// Checks whether the Remove() method is working via the
+ /// generic ICollection<> interface
+ ///
+ [Test]
+ public void TestRemoveViaGenericICollection() {
+ IEnumerator> enumerator =
+ (this.observedDictionary as ICollection>).GetEnumerator();
+ enumerator.MoveNext();
+ Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
+ (this.observedDictionary as ICollection>).Remove(
+ enumerator.Current
+ );
+ this.mockery.VerifyAllExpectationsHaveBeenMet();
+
+ CollectionAssert.DoesNotContain(this.observedDictionary, enumerator.Current);
+ }
+
+ ///
+ /// Verifies that the CopyTo() of the observable dictionary works when called
+ /// via the the ICollection interface
+ ///
+ [Test]
+ public void TestCopyToArrayViaICollection() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ DictionaryEntry[] entries = new DictionaryEntry[numbers.Count];
+ (testDictionary as ICollection).CopyTo(entries, 0);
+
+ KeyValuePair[] items = new KeyValuePair[numbers.Count];
+ for(int index = 0; index < entries.Length; ++index) {
+ items[index] = new KeyValuePair(
+ (int)entries[index].Key, (string)entries[index].Value
+ );
+ }
+ CollectionAssert.AreEquivalent(numbers, items);
+ }
+
+ ///
+ /// Verifies that the IsSynchronized property and the SyncRoot property are working
+ ///
+ [Test]
+ public void TestSynchronization() {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary = makeObservable(numbers);
+
+ if(!(testDictionary as ICollection).IsSynchronized) {
+ lock((testDictionary as ICollection).SyncRoot) {
+ Assert.AreEqual(numbers.Count, testDictionary.Count);
+ }
+ }
+ }
+
+ ///
+ /// Test whether the observable dictionary can be serialized
+ ///
+ [Test]
+ public void TestSerialization() {
+ BinaryFormatter formatter = new BinaryFormatter();
+
+ using(MemoryStream memory = new MemoryStream()) {
+ Dictionary numbers = createTestDictionary();
+ ObservableDictionary testDictionary1 = makeObservable(numbers);
+
+ formatter.Serialize(memory, testDictionary1);
+ memory.Position = 0;
+ object testDictionary2 = formatter.Deserialize(memory);
+
+ CollectionAssert.AreEquivalent(testDictionary1, (IEnumerable)testDictionary2);
+ }
+ }
+
+ ///
+ /// Creates a new observable dictionary filled with some values for testing
+ ///
+ /// The newly created observable dictionary
+ private static Dictionary createTestDictionary() {
+ Dictionary numbers = new Dictionary();
+ numbers.Add(1, "one");
+ numbers.Add(2, "two");
+ numbers.Add(3, "three");
+ numbers.Add(42, "forty-two");
+ return new Dictionary(numbers);
+ }
+
+ ///
+ /// Creates a new observable dictionary filled with some values for testing
+ ///
+ /// The newly created observable dictionary
+ private static ObservableDictionary makeObservable(
+ IDictionary dictionary
+ ) {
+ return new ObservableDictionary(dictionary);
+ }
+
+ /// Mock object factory
+ private Mockery mockery;
+ /// The mocked observable collection subscriber
+ private IObservableDictionarySubscriber mockedSubscriber;
+ /// An observable dictionary to which a mock will be subscribed
+ private ObservableDictionary observedDictionary;
+
+ }
+
+} // namespace Nuclex.Support.Collections
+
+#endif // UNITTEST
diff --git a/Source/Collections/ObservableDictionary.cs b/Source/Collections/ObservableDictionary.cs
new file mode 100644
index 0000000..7c01243
--- /dev/null
+++ b/Source/Collections/ObservableDictionary.cs
@@ -0,0 +1,405 @@
+#region CPL License
+/*
+Nuclex Framework
+Copyright (C) 2002-2009 Nuclex Development Labs
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the IBM Common Public License as
+published by the IBM Corporation; either version 1.0 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+IBM Common Public License for more details.
+
+You should have received a copy of the IBM Common Public
+License along with this library
+*/
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Collections.ObjectModel;
+using System.Runtime.Serialization;
+
+namespace Nuclex.Support.Collections {
+
+ /// A dictionary that sneds out change notifications
+ /// Type of the keys used in the dictionary
+ /// Type of the values used in the dictionary
+ [Serializable]
+ public class ObservableDictionary :
+#if !COMPACTFRAMEWORK
+ ISerializable,
+ IDeserializationCallback,
+#endif
+ IDictionary,
+ IDictionary {
+
+#if !COMPACTFRAMEWORK
+ #region class SerializedDictionary
+
+ ///
+ /// Dictionary wrapped used to reconstruct a serialized read only dictionary
+ ///
+ private class SerializedDictionary : Dictionary {
+
+ ///
+ /// Initializes a new instance of the System.WeakReference class, using deserialized
+ /// data from the specified serialization and stream objects.
+ ///
+ ///
+ /// An object that holds all the data needed to serialize or deserialize the
+ /// current System.WeakReference object.
+ ///
+ ///
+ /// (Reserved) Describes the source and destination of the serialized stream
+ /// specified by info.
+ ///
+ ///
+ /// The info parameter is null.
+ ///
+ public SerializedDictionary(SerializationInfo info, StreamingContext context) :
+ base(info, context) { }
+
+ }
+
+ #endregion // class SerializeDictionary
+#endif // !COMPACTFRAMEWORK
+
+ /// Raised when an item has been added to the dictionary
+ public event EventHandler>> ItemAdded;
+ /// Raised when an item is removed from the dictionary
+ public event EventHandler>> ItemRemoved;
+ /// Raised when the dictionary is about to be cleared
+ public event EventHandler Clearing;
+
+ /// Initializes a new observable dictionary
+ public ObservableDictionary() : this(new Dictionary()) { }
+
+ /// Initializes a new observable Dictionary wrapper
+ /// Dictionary that will be wrapped
+ public ObservableDictionary(IDictionary dictionary) {
+ this.typedDictionary = dictionary;
+ this.objectDictionary = (this.typedDictionary as IDictionary);
+ }
+
+#if !COMPACTFRAMEWORK
+ ///
+ /// Initializes a new instance of the System.WeakReference class, using deserialized
+ /// data from the specified serialization and stream objects.
+ ///
+ ///
+ /// An object that holds all the data needed to serialize or deserialize the
+ /// current System.WeakReference object.
+ ///
+ ///
+ /// (Reserved) Describes the source and destination of the serialized stream
+ /// specified by info.
+ ///
+ ///
+ /// The info parameter is null.
+ ///
+ protected ObservableDictionary(SerializationInfo info, StreamingContext context) :
+ this(new SerializedDictionary(info, context)) { }
+#endif // !COMPACTFRAMEWORK
+
+ /// Whether the directory is write-protected
+ public bool IsReadOnly {
+ get { return this.typedDictionary.IsReadOnly; }
+ }
+
+ ///
+ /// Determines whether the specified KeyValuePair is contained in the Dictionary
+ ///
+ /// KeyValuePair that will be checked for
+ /// True if the provided KeyValuePair was contained in the Dictionary
+ public bool Contains(KeyValuePair item) {
+ return this.typedDictionary.Contains(item);
+ }
+
+ /// Determines whether the Dictionary contains the specified key
+ /// Key that will be checked for
+ ///
+ /// True if an entry with the specified key was contained in the Dictionary
+ ///
+ public bool ContainsKey(KeyType key) {
+ return this.typedDictionary.ContainsKey(key);
+ }
+
+ /// Copies the contents of the Dictionary into an array
+ /// Array the Dictionary will be copied into
+ ///
+ /// Starting index at which to begin filling the destination array
+ ///
+ public void CopyTo(KeyValuePair[] array, int arrayIndex) {
+ this.typedDictionary.CopyTo(array, arrayIndex);
+ }
+
+ /// Number of elements contained in the Dictionary
+ public int Count {
+ get { return this.typedDictionary.Count; }
+ }
+
+ /// Creates a new enumerator for the Dictionary
+ /// The new Dictionary enumerator
+ public IEnumerator> GetEnumerator() {
+ return this.typedDictionary.GetEnumerator();
+ }
+
+ /// Collection of all keys contained in the Dictionary
+ public ICollection Keys {
+ get { return this.typedDictionary.Keys; }
+ }
+
+ /// Collection of all values contained in the Dictionary
+ public ICollection Values {
+ get { return this.typedDictionary.Values; }
+ }
+
+ ///
+ /// Attempts to retrieve the item with the specified key from the Dictionary
+ ///
+ /// Key of the item to attempt to retrieve
+ ///
+ /// Output parameter that will receive the key upon successful completion
+ ///
+ ///
+ /// True if the item was found and has been placed in the output parameter
+ ///
+ public bool TryGetValue(KeyType key, out ValueType value) {
+ return this.typedDictionary.TryGetValue(key, out value);
+ }
+
+ /// Accesses an item in the Dictionary by its key
+ /// Key of the item that will be accessed
+ public ValueType this[KeyType key] {
+ get { return this.typedDictionary[key]; }
+ set {
+ bool removed;
+ ValueType oldValue;
+ removed = this.typedDictionary.TryGetValue(key, out oldValue);
+
+ this.typedDictionary[key] = value;
+
+ if(removed) {
+ OnRemoved(new KeyValuePair(key, oldValue));
+ }
+ OnAdded(new KeyValuePair(key, value));
+ }
+ }
+
+ /// Inserts an item into the Dictionary
+ /// Key under which to add the new item
+ /// Item that will be added to the Dictionary
+ public void Add(KeyType key, ValueType value) {
+ this.typedDictionary.Add(key, value);
+ OnAdded(new KeyValuePair(key, value));
+ }
+
+ /// Removes the item with the specified key from the Dictionary
+ /// Key of the elementes that will be removed
+ /// True if an item with the specified key was found and removed
+ public bool Remove(KeyType key) {
+ ValueType oldValue;
+ this.typedDictionary.TryGetValue(key, out oldValue);
+
+ bool removed = this.typedDictionary.Remove(key);
+ if(removed) {
+ OnRemoved(new KeyValuePair(key, oldValue));
+ }
+ return removed;
+ }
+
+ /// Removes all items from the Dictionary
+ public void Clear() {
+ OnClearing();
+ this.typedDictionary.Clear();
+ }
+
+ /// Fires the 'ItemAdded' event
+ /// Item that has been added to the collection
+ protected virtual void OnAdded(KeyValuePair item) {
+ if(ItemAdded != null)
+ ItemAdded(this, new ItemEventArgs>(item));
+ }
+
+ /// Fires the 'ItemRemoved' event
+ /// Item that has been removed from the collection
+ protected virtual void OnRemoved(KeyValuePair item) {
+ if(ItemRemoved != null)
+ ItemRemoved(this, new ItemEventArgs>(item));
+ }
+
+ /// Fires the 'Clearing' event
+ protected virtual void OnClearing() {
+ if(Clearing != null)
+ Clearing(this, EventArgs.Empty);
+ }
+
+ #region IEnumerable implementation
+
+ /// Returns a new object enumerator for the Dictionary
+ /// The new object enumerator
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return (this.typedDictionary as IEnumerable).GetEnumerator();
+ }
+
+ #endregion
+
+ #region IDictionary implementation
+
+ /// Adds an item into the Dictionary
+ /// Key under which the item will be added
+ /// Item that will be added
+ void IDictionary.Add(object key, object value) {
+ this.objectDictionary.Add(key, value);
+ OnAdded(new KeyValuePair((KeyType)key, (ValueType)value));
+ }
+
+ /// Determines whether the specified key exists in the Dictionary
+ /// Key that will be checked for
+ /// True if an item with the specified key exists in the Dictionary
+ bool IDictionary.Contains(object key) {
+ return this.objectDictionary.Contains(key);
+ }
+
+ /// Returns a new entry enumerator for the dictionary
+ /// The new entry enumerator
+ IDictionaryEnumerator IDictionary.GetEnumerator() {
+ return this.objectDictionary.GetEnumerator();
+ }
+
+ /// Whether the size of the Dictionary is fixed
+ bool IDictionary.IsFixedSize {
+ get { return this.objectDictionary.IsFixedSize; }
+ }
+
+ /// Returns a collection of all keys in the Dictionary
+ ICollection IDictionary.Keys {
+ get { return this.objectDictionary.Keys; }
+ }
+
+ /// Returns a collection of all values stored in the Dictionary
+ ICollection IDictionary.Values {
+ get { return this.objectDictionary.Values; }
+ }
+
+ /// Removes an item from the Dictionary
+ /// Key of the item that will be removed
+ void IDictionary.Remove(object key) {
+ ValueType value;
+ bool removed = this.typedDictionary.TryGetValue((KeyType)key, out value);
+ this.objectDictionary.Remove(key);
+ if(removed) {
+ OnRemoved(new KeyValuePair((KeyType)key, (ValueType)value));
+ }
+ }
+
+ /// Accesses an item in the Dictionary by its key
+ /// Key of the item that will be accessed
+ /// The item with the specified key
+ object IDictionary.this[object key] {
+ get { return this.objectDictionary[key]; }
+ set {
+ bool removed;
+ ValueType oldValue;
+ removed = this.typedDictionary.TryGetValue((KeyType)key, out oldValue);
+
+ this.objectDictionary[key] = value;
+
+ if(removed) {
+ OnRemoved(new KeyValuePair((KeyType)key, oldValue));
+ }
+ OnAdded(new KeyValuePair((KeyType)key, (ValueType)value));
+ }
+ }
+
+ #endregion
+
+ #region ICollection<> implementation
+
+ /// Inserts an already prepared element into the Dictionary
+ /// Prepared element that will be added to the Dictionary
+ void ICollection>.Add(
+ KeyValuePair item
+ ) {
+ this.typedDictionary.Add(item);
+ OnAdded(item);
+ }
+
+ /// Removes all items from the Dictionary
+ void ICollection>.Clear() {
+ OnClearing();
+ this.typedDictionary.Clear();
+ }
+
+ /// Removes all items from the Dictionary
+ /// Item that will be removed from the Dictionary
+ bool ICollection>.Remove(
+ KeyValuePair itemToRemove
+ ) {
+ bool removed = this.typedDictionary.Remove(itemToRemove);
+ if(removed) {
+ OnRemoved(itemToRemove);
+ }
+ return removed;
+ }
+
+ #endregion
+
+ #region ICollection implementation
+
+ /// Copies the contents of the Dictionary into an array
+ /// Array the Dictionary contents will be copied into
+ ///
+ /// Starting index at which to begin filling the destination array
+ ///
+ void ICollection.CopyTo(Array array, int index) {
+ this.objectDictionary.CopyTo(array, index);
+ }
+
+ /// Whether the Dictionary is synchronized for multi-threaded usage
+ bool ICollection.IsSynchronized {
+ get { return this.objectDictionary.IsSynchronized; }
+ }
+
+ /// Synchronization root on which the Dictionary locks
+ object ICollection.SyncRoot {
+ get { return this.objectDictionary.SyncRoot; }
+ }
+
+ #endregion
+
+#if !COMPACTFRAMEWORK
+ #region ISerializable implementation
+
+ /// Serializes the Dictionary
+ ///
+ /// Provides the container into which the Dictionary will serialize itself
+ ///
+ ///
+ /// Contextual informations about the serialization environment
+ ///
+ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
+ (this.typedDictionary as ISerializable).GetObjectData(info, context);
+ }
+
+ /// Called after all objects have been successfully deserialized
+ /// Nicht unterstützt
+ void IDeserializationCallback.OnDeserialization(object sender) {
+ (this.typedDictionary as IDeserializationCallback).OnDeserialization(sender);
+ }
+
+ #endregion
+#endif //!COMPACTFRAMEWORK
+
+ /// The wrapped Dictionary under its type-safe interface
+ private IDictionary typedDictionary;
+ /// The wrapped Dictionary under its object interface
+ private IDictionary objectDictionary;
+ }
+
+} // namespace Nuclex.Support.Collections
diff --git a/Source/Collections/ReadOnlyDictionary.Test.cs b/Source/Collections/ReadOnlyDictionary.Test.cs
index befbf2e..4f3d363 100644
--- a/Source/Collections/ReadOnlyDictionary.Test.cs
+++ b/Source/Collections/ReadOnlyDictionary.Test.cs
@@ -188,7 +188,7 @@ namespace Nuclex.Support.Collections {
/// Add() method is called via the generic IDictionary<> interface
///
[Test, ExpectedException(typeof(NotSupportedException))]
- public void TestThrowOnAddAtViaGenericIDictionary() {
+ public void TestThrowOnAddViaGenericIDictionary() {
Dictionary numbers = createTestDictionary();
ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
@@ -388,7 +388,7 @@ namespace Nuclex.Support.Collections {
///
/// Checks whether the read only dictionary will throw an exception if its
- /// Clear() method is used via the generic ICollection<> interface
+ /// Remove() method is used via the generic ICollection<> interface
///
[Test, ExpectedException(typeof(NotSupportedException))]
public void TestThrowOnRemoveViaGenericICollection() {
@@ -396,7 +396,7 @@ namespace Nuclex.Support.Collections {
ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
(testDictionary as ICollection>).Remove(
- new KeyValuePair(24, "twenty-four")
+ new KeyValuePair(42, "fourty-two")
);
}
diff --git a/Source/Collections/ReadOnlyDictionary.cs b/Source/Collections/ReadOnlyDictionary.cs
index 7d0e52d..b0f1c64 100644
--- a/Source/Collections/ReadOnlyDictionary.cs
+++ b/Source/Collections/ReadOnlyDictionary.cs
@@ -26,9 +26,9 @@ using System.Runtime.Serialization;
namespace Nuclex.Support.Collections {
- /// Wraps a Dictionary and prevents users from modifying it
- /// Type of the keys used in the Dictionary
- /// Type of the values used in the Dictionary
+ /// Wraps a dictionary and prevents users from modifying it
+ /// Type of the keys used in the dictionary
+ /// Type of the values used in the dictionary
[Serializable]
public class ReadOnlyDictionary :
#if !COMPACTFRAMEWORK
@@ -89,7 +89,7 @@ namespace Nuclex.Support.Collections {
#endif // !COMPACTFRAMEWORK
- /// Initializes a new read-only Dictionary wrapper
+ /// Initializes a new read-only dictionary wrapper
/// Dictionary that will be wrapped
public ReadOnlyDictionary(IDictionary dictionary) {
this.typedDictionary = dictionary;