diff --git a/Source/Collections/ReadOnlyDictionary.Test.cs b/Source/Collections/ReadOnlyDictionary.Test.cs
index 0c0894a..f109d01 100644
--- a/Source/Collections/ReadOnlyDictionary.Test.cs
+++ b/Source/Collections/ReadOnlyDictionary.Test.cs
@@ -21,6 +21,8 @@ License along with this library
using System;
using System.Collections;
using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
#if UNITTEST
@@ -32,6 +34,442 @@ namespace Nuclex.Support.Collections {
[TestFixture]
public class ReadOnlyDictionaryTest {
+ ///
+ /// Verifies that the copy constructor of the read only dictionary works
+ ///
+ [Test]
+ public void TestCopyConstructor() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ CollectionAssert.AreEqual(numbers, testDictionary);
+ }
+
+ /// Verifies that the IsReadOnly property returns true
+ [Test]
+ public void TestIsReadOnly() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Assert.IsTrue(testDictionary.IsReadOnly);
+ }
+
+ ///
+ /// Checks whether the Contains() method of the read only dictionary is able to
+ /// determine if the dictionary contains an item
+ ///
+ [Test]
+ public void TestContains() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(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 read only dictionary is able to
+ /// determine if the dictionary contains a key
+ ///
+ [Test]
+ public void TestContainsKey() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Assert.IsTrue(testDictionary.ContainsKey(42));
+ Assert.IsFalse(testDictionary.ContainsKey(24));
+ }
+
+ ///
+ /// Verifies that the CopyTo() of the read only dictionary works
+ ///
+ [Test]
+ public void TestCopyToArray() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ KeyValuePair[] items = new KeyValuePair[numbers.Count];
+
+ testDictionary.CopyTo(items, 0);
+
+ CollectionAssert.AreEqual(numbers, items);
+ }
+
+ ///
+ /// Tests whether the typesafe enumerator of the read only dictionary is working
+ ///
+ [Test]
+ public void TestTypesafeEnumerator() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ List> outputItems = new List>();
+ foreach(KeyValuePair item in testDictionary) {
+ outputItems.Add(item);
+ }
+
+ CollectionAssert.AreEqual(numbers, outputItems);
+ }
+
+ ///
+ /// Tests whether the keys collection of the read only dictionary can be queried
+ ///
+ [Test]
+ public void TestGetKeysCollection() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ ICollection inputKeys = numbers.Keys;
+ ICollection keys = testDictionary.Keys;
+ CollectionAssert.AreEqual(inputKeys, keys);
+ }
+
+ ///
+ /// Tests whether the values collection of the read only dictionary can be queried
+ ///
+ [Test]
+ public void TestGetValuesCollection() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ ICollection inputValues = numbers.Values;
+ ICollection values = testDictionary.Values;
+ CollectionAssert.AreEqual(inputValues, values);
+ }
+
+ ///
+ /// Tests whether the TryGetValue() method of the read only dictionary is working
+ ///
+ [Test]
+ public void TestTryGetValue() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ string value;
+
+ Assert.IsTrue(testDictionary.TryGetValue(42, out value));
+ Assert.AreEqual("forty-two", value);
+
+ Assert.IsFalse(testDictionary.TryGetValue(24, out value));
+ Assert.AreEqual(null, value);
+ }
+
+ ///
+ /// Tests whether the retrieval of values using the indexer of the read only
+ /// dictionary is working
+ ///
+ [Test]
+ public void TestRetrieveValueByIndexer() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Assert.AreEqual("forty-two", testDictionary[42]);
+ }
+
+ ///
+ /// Tests whether an exception is thrown if the indexer of the read only dictionary
+ /// is used to attempt to retrieve a non-existing value
+ ///
+ [Test, ExpectedException(typeof(KeyNotFoundException))]
+ public void TestThrowOnRetrieveNonExistingValueByIndexer() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ string numberName = testDictionary[24];
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Add() method is called via the generic IDictionary<> interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnAddAtViaGenericIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as IDictionary).Add(10, "ten");
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Remove() method is called via the generic IDictionary<> interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnRemoveViaGenericIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as IDictionary).Remove(3);
+ }
+
+ ///
+ /// Tests whether the TryGetValue() method of the read only dictionary is working
+ ///
+ [Test]
+ public void TestRetrieveValueByIndexerViaGenericIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Assert.AreEqual("forty-two", (testDictionary as IDictionary)[42]);
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// indexer is used to insert an item via the generic IDictionar<> interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnReplaceByIndexerViaGenericIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as IDictionary)[24] = "twenty-four";
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Clear() method is called via the IDictionary interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnClearViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as IDictionary).Clear();
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Add() method is called via the IDictionary interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnAddViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as IDictionary).Add(24, "twenty-four");
+ }
+
+ ///
+ /// Checks whether the Contains() method of the read only dictionary is able to
+ /// determine if the dictionary contains an item via the IDictionary interface
+ ///
+ [Test]
+ public void TestContainsViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Assert.IsTrue((testDictionary as IDictionary).Contains(42));
+ Assert.IsFalse((testDictionary as IDictionary).Contains(24));
+ }
+
+ ///
+ /// Checks whether the GetEnumerator() method of the read only dictionary returns
+ /// a working enumerator if accessed via the IDictionary interface
+ ///
+ [Test]
+ public void TestEnumeratorViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Dictionary outputNumbers = new Dictionary();
+ foreach(DictionaryEntry entry in (testDictionary as IDictionary)) {
+ (outputNumbers as IDictionary).Add(entry.Key, entry.Value);
+ }
+
+ CollectionAssert.AreEqual(numbers, outputNumbers);
+ }
+
+ ///
+ /// Checks whether the IsFixedSize property of the read only dictionary returns
+ /// the expected result for a read only dictionary based on a dynamic dictionary
+ ///
+ [Test]
+ public void TestIsFixedSizeViaIList() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Assert.IsFalse((testDictionary as IDictionary).IsFixedSize);
+ }
+
+ ///
+ /// Tests whether the keys collection of the read only dictionary can be queried
+ /// via the IDictionary interface
+ ///
+ [Test]
+ public void TestGetKeysCollectionViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ ICollection inputKeys = (numbers as IDictionary).Keys;
+ ICollection keys = (testDictionary as IDictionary).Keys;
+ CollectionAssert.AreEqual(inputKeys, keys);
+ }
+
+ ///
+ /// Tests whether the values collection of the read only dictionary can be queried
+ /// via the IDictionary interface
+ ///
+ [Test]
+ public void TestGetValuesCollectionViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ ICollection inputValues = (numbers as IDictionary).Values;
+ ICollection values = (testDictionary as IDictionary).Values;
+ CollectionAssert.AreEqual(inputValues, values);
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Remove() method is called via the IDictionary interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnRemoveViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as IDictionary).Remove(3);
+ }
+
+ ///
+ /// Tests whether the retrieval of values using the indexer of the read only
+ /// dictionary is working via the IDictionary interface
+ ///
+ [Test]
+ public void TestRetrieveValueByIndexerViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ Assert.AreEqual("forty-two", (testDictionary as IDictionary)[42]);
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// indexer is used to insert an item via the IDictionary interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnReplaceByIndexerViaIDictionary() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as IDictionary)[24] = "twenty-four";
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Add() method is used via the generic ICollection<> interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnAddViaGenericICollection() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as ICollection>).Add(
+ new KeyValuePair(24, "twenty-four")
+ );
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Clear() method is used via the generic ICollection<> interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnClearViaGenericICollection() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as ICollection>).Clear();
+ }
+
+ ///
+ /// Checks whether the read only dictionary will throw an exception if its
+ /// Clear() method is used via the generic ICollection<> interface
+ ///
+ [Test, ExpectedException(typeof(NotSupportedException))]
+ public void TestThrowOnRemoveViaGenericICollection() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ (testDictionary as ICollection>).Remove(
+ new KeyValuePair(24, "twenty-four")
+ );
+ }
+
+ ///
+ /// Verifies that the CopyTo() of the read only dictionary works when called
+ /// via the the ICollection interface
+ ///
+ [Test]
+ public void TestCopyToArrayViaICollection() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ KeyValuePair[] items = new KeyValuePair[numbers.Count];
+ (testDictionary as ICollection).CopyTo(items, 0);
+ CollectionAssert.AreEqual(numbers, items);
+ }
+
+ ///
+ /// Verifies that the IsSynchronized property and the SyncRoot property are working
+ ///
+ [Test]
+ public void TestSynchronization() {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary = makeReadOnly(numbers);
+
+ if(!(testDictionary as ICollection).IsSynchronized) {
+ lock((testDictionary as ICollection).SyncRoot) {
+ int count = testDictionary.Count;
+ }
+ }
+ }
+
+ ///
+ /// Test whether the read only dictionary can be serialized
+ ///
+ [Test]
+ public void TestSerialization() {
+ BinaryFormatter formatter = new BinaryFormatter();
+
+ using(MemoryStream memory = new MemoryStream()) {
+ Dictionary numbers = createTestDictionary();
+ ReadOnlyDictionary testDictionary1 = makeReadOnly(numbers);
+
+ formatter.Serialize(memory, testDictionary1);
+ memory.Position = 0;
+ object testDictionary2 = formatter.Deserialize(memory);
+
+ CollectionAssert.AreEqual(testDictionary1, (IEnumerable)testDictionary2);
+ }
+ }
+
+ ///
+ /// Creates a new read-only dictionary filled with some values for testing
+ ///
+ /// The newly created read-only 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 read-only dictionary filled with some values for testing
+ ///
+ /// The newly created read-only dictionary
+ private static ReadOnlyDictionary makeReadOnly(
+ IDictionary dictionary
+ ) {
+ return new ReadOnlyDictionary(dictionary);
+ }
+
}
} // namespace Nuclex.Support.Collections
diff --git a/Source/Collections/ReadOnlyDictionary.cs b/Source/Collections/ReadOnlyDictionary.cs
index fbbfc76..7310df7 100644
--- a/Source/Collections/ReadOnlyDictionary.cs
+++ b/Source/Collections/ReadOnlyDictionary.cs
@@ -29,12 +29,42 @@ 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
+ [Serializable]
public class ReadOnlyDictionary :
IDictionary,
IDictionary,
ISerializable,
IDeserializationCallback {
+ #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
+
/// Initializes a new read-only Dictionary wrapper
/// Dictionary that will be wrapped
public ReadOnlyDictionary(IDictionary dictionary) {
@@ -42,6 +72,24 @@ namespace Nuclex.Support.Collections {
this.objectDictionary = (this.typedDictionary as IDictionary);
}
+ ///
+ /// 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 ReadOnlyDictionary(SerializationInfo info, StreamingContext context) :
+ this(new SerializedDictionary(info, context)) { }
+
/// Whether the directory is write-protected
public bool IsReadOnly {
get { return true; }
diff --git a/Source/Collections/ReadOnlyList.Test.cs b/Source/Collections/ReadOnlyList.Test.cs
index ed623e9..6b4b84f 100644
--- a/Source/Collections/ReadOnlyList.Test.cs
+++ b/Source/Collections/ReadOnlyList.Test.cs
@@ -187,7 +187,7 @@ namespace Nuclex.Support.Collections {
}
///
- /// Tests whether the typesafe enumerator of the read only collection is working
+ /// Tests whether the typesafe enumerator of the read only list is working
///
[Test]
public void TestTypesafeEnumerator() {