Added new class ObservableDictionary to the collection class library; 100% test coverage for the new ObservableDictionary class; fixed some minor issues with the code of ObservableCollection and ReadOnlyDictionary
git-svn-id: file:///srv/devel/repo-conversion/nusu@117 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
f0498fbb60
commit
b90ff1c78b
|
@ -77,6 +77,10 @@
|
|||
<Compile Include="Source\Collections\ObservableCollection.Test.cs">
|
||||
<DependentUpon>ObservableCollection.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Collections\ObservableDictionary.cs" />
|
||||
<Compile Include="Source\Collections\ObservableDictionary.Test.cs">
|
||||
<DependentUpon>ObservableDictionary.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Collections\PairPriorityQueue.cs" />
|
||||
<Compile Include="Source\Collections\PairPriorityQueue.Test.cs">
|
||||
<DependentUpon>PairPriorityQueue.cs</DependentUpon>
|
||||
|
|
|
@ -59,6 +59,10 @@
|
|||
<Compile Include="Source\Collections\ObservableCollection.Test.cs">
|
||||
<DependentUpon>ObservableCollection.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Collections\ObservableDictionary.cs" />
|
||||
<Compile Include="Source\Collections\ObservableDictionary.Test.cs">
|
||||
<DependentUpon>ObservableDictionary.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Collections\PairPriorityQueue.cs" />
|
||||
<Compile Include="Source\Collections\PairPriorityQueue.Test.cs">
|
||||
<DependentUpon>PairPriorityQueue.cs</DependentUpon>
|
||||
|
|
|
@ -34,23 +34,23 @@ namespace Nuclex.Support.Collections {
|
|||
|
||||
#region interface IObservableCollectionSubscriber
|
||||
|
||||
/// <summary>Interface used to test the observable collection.</summary>
|
||||
/// <summary>Interface used to test the observable collection</summary>
|
||||
public interface IObservableCollectionSubscriber {
|
||||
|
||||
/// <summary>Called when the collection is about to clear its contents</summary>
|
||||
/// <param name="sender">Collection that is clearing its contents</param>
|
||||
/// <param name="e">Not used</param>
|
||||
void Clearing(object sender, EventArgs e);
|
||||
/// <param name="arguments">Not used</param>
|
||||
void Clearing(object sender, EventArgs arguments);
|
||||
|
||||
/// <summary>Called when an item is added to the collection</summary>
|
||||
/// <param name="sender">Collection to which an item is being added</param>
|
||||
/// <param name="e">Contains the item that is being added</param>
|
||||
void ItemAdded(object sender, ItemEventArgs<int> e);
|
||||
/// <param name="arguments">Contains the item that is being added</param>
|
||||
void ItemAdded(object sender, ItemEventArgs<int> arguments);
|
||||
|
||||
/// <summary>Called when an item is removed from the collection</summary>
|
||||
/// <param name="sender">Collection from which an item is being removed</param>
|
||||
/// <param name="e">Contains the item that is being removed</param>
|
||||
void ItemRemoved(object sender, ItemEventArgs<int> e);
|
||||
/// <param name="arguments">Contains the item that is being removed</param>
|
||||
void ItemRemoved(object sender, ItemEventArgs<int> arguments);
|
||||
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,6 @@ namespace Nuclex.Support.Collections {
|
|||
new EventHandler<ItemEventArgs<int>>(
|
||||
this.mockedSubscriber.ItemRemoved
|
||||
);
|
||||
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
}
|
||||
|
||||
/// <summary>Tests whether the Clearing event is fired</summary>
|
||||
|
|
539
Source/Collections/ObservableDictionary.Test.cs
Normal file
539
Source/Collections/ObservableDictionary.Test.cs
Normal file
|
@ -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 {
|
||||
|
||||
/// <summary>Unit Test for the observable dictionary wrapper</summary>
|
||||
[TestFixture]
|
||||
public class ObservableDictionaryTest {
|
||||
|
||||
#region interface IObservableDictionarySubscriber
|
||||
|
||||
/// <summary>Interface used to test the observable dictionary</summary>
|
||||
public interface IObservableDictionarySubscriber {
|
||||
|
||||
/// <summary>Called when the dictionary is about to clear its contents</summary>
|
||||
/// <param name="sender">Dictionary that is clearing its contents</param>
|
||||
/// <param name="arguments">Not used</param>
|
||||
void Clearing(object sender, EventArgs arguments);
|
||||
|
||||
/// <summary>Called when an item is added to the dictionary</summary>
|
||||
/// <param name="sender">Dictionary to which an item is being added</param>
|
||||
/// <param name="arguments">Contains the item that is being added</param>
|
||||
void ItemAdded(object sender, ItemEventArgs<KeyValuePair<int, string>> arguments);
|
||||
|
||||
/// <summary>Called when an item is removed from the dictionary</summary>
|
||||
/// <param name="sender">Dictionary from which an item is being removed</param>
|
||||
/// <param name="arguments">Contains the item that is being removed</param>
|
||||
void ItemRemoved(object sender, ItemEventArgs<KeyValuePair<int, string>> arguments);
|
||||
|
||||
}
|
||||
|
||||
#endregion // interface IObservableDictionarySubscriber
|
||||
|
||||
/// <summary>Initialization routine executed before each test is run</summary>
|
||||
[SetUp]
|
||||
public void Setup() {
|
||||
this.mockery = new Mockery();
|
||||
|
||||
this.mockedSubscriber = this.mockery.NewMock<IObservableDictionarySubscriber>();
|
||||
|
||||
this.observedDictionary = new ObservableDictionary<int, string>();
|
||||
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<ItemEventArgs<KeyValuePair<int, string>>>(
|
||||
this.mockedSubscriber.ItemAdded
|
||||
);
|
||||
this.observedDictionary.ItemRemoved +=
|
||||
new EventHandler<ItemEventArgs<KeyValuePair<int, string>>>(
|
||||
this.mockedSubscriber.ItemRemoved
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the default constructor of the observable dictionary works
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDefaultConstructor() {
|
||||
ObservableDictionary<int, string> testDictionary =
|
||||
new ObservableDictionary<int, string>();
|
||||
|
||||
Assert.AreEqual(0, testDictionary.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the copy constructor of the observable dictionary works
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCopyConstructor() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
CollectionAssert.AreEqual(numbers, testDictionary);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the IsReadOnly property is working</summary>
|
||||
[Test]
|
||||
public void TestIsReadOnly() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
Assert.IsFalse(testDictionary.IsReadOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Contains() method of the observable dictionary is able to
|
||||
/// determine if the dictionary contains an item
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestContains() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
Assert.IsTrue(
|
||||
testDictionary.Contains(new KeyValuePair<int, string>(42, "forty-two"))
|
||||
);
|
||||
Assert.IsFalse(
|
||||
testDictionary.Contains(new KeyValuePair<int, string>(24, "twenty-four"))
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Contains() method of the observable dictionary is able to
|
||||
/// determine if the dictionary contains a key
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestContainsKey() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
Assert.IsTrue(testDictionary.ContainsKey(42));
|
||||
Assert.IsFalse(testDictionary.ContainsKey(24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the CopyTo() of the observable dictionary works
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCopyToArray() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
KeyValuePair<int, string>[] items = new KeyValuePair<int, string>[numbers.Count];
|
||||
|
||||
testDictionary.CopyTo(items, 0);
|
||||
|
||||
CollectionAssert.AreEqual(numbers, items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the typesafe enumerator of the observable dictionary is working
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestTypesafeEnumerator() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
List<KeyValuePair<int, string>> outputItems = new List<KeyValuePair<int, string>>();
|
||||
foreach(KeyValuePair<int, string> item in testDictionary) {
|
||||
outputItems.Add(item);
|
||||
}
|
||||
|
||||
CollectionAssert.AreEqual(numbers, outputItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the keys collection of the observable dictionary can be queried
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetKeysCollection() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
ICollection<int> inputKeys = numbers.Keys;
|
||||
ICollection<int> keys = testDictionary.Keys;
|
||||
CollectionAssert.AreEquivalent(inputKeys, keys);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the values collection of the observable dictionary can be queried
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetValuesCollection() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
ICollection<string> inputValues = numbers.Values;
|
||||
ICollection<string> values = testDictionary.Values;
|
||||
CollectionAssert.AreEquivalent(inputValues, values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the TryGetValue() method of the observable dictionary is working
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the retrieval of values using the indexer of the observable
|
||||
/// dictionary is working
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRetrieveValueByIndexer() {
|
||||
Assert.AreEqual("forty-two", this.observedDictionary[42]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether an exception is thrown if the indexer of the observable dictionary
|
||||
/// is used to attempt to retrieve a non-existing value
|
||||
/// </summary>
|
||||
[Test, ExpectedException(typeof(KeyNotFoundException))]
|
||||
public void TestThrowOnRetrieveNonExistingValueByIndexer() {
|
||||
string numberName = this.observedDictionary[24];
|
||||
Console.WriteLine(numberName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Add() methods works via the generic
|
||||
/// IDictionary<> interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddViaGenericIDictionary() {
|
||||
Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
|
||||
(this.observedDictionary as IDictionary<int, string>).Add(10, "ten");
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
|
||||
CollectionAssert.Contains(
|
||||
this.observedDictionary, new KeyValuePair<int, string>(10, "ten")
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Remove() method works via the generic
|
||||
/// IDictionary<> interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRemoveViaGenericIDictionary() {
|
||||
Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
|
||||
(this.observedDictionary as IDictionary<int, string>).Remove(3);
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
|
||||
CollectionAssert.DoesNotContain(this.observedDictionary.Keys, 3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the TryGetValue() method of the observable dictionary is working
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRetrieveValueByIndexerViaGenericIDictionary() {
|
||||
Assert.AreEqual(
|
||||
"forty-two", (this.observedDictionary as IDictionary<int, string>)[42]
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the indexer can be used to insert an item via the generic
|
||||
/// IDictionar<> interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReplaceByIndexerViaGenericIDictionary() {
|
||||
Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
|
||||
Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
|
||||
(this.observedDictionary as IDictionary<int, string>)[42] = "two and fourty";
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
|
||||
Assert.AreEqual("two and fourty", this.observedDictionary[42]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Clear() method of observable dictionary is working
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Add() method works via the IDictionary interface
|
||||
/// </summary>
|
||||
[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<int, string>(24, "twenty-four")
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Contains() method of the observable dictionary is able to
|
||||
/// determine if the dictionary contains an item via the IDictionary interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestContainsViaIDictionary() {
|
||||
Assert.IsTrue((this.observedDictionary as IDictionary).Contains(42));
|
||||
Assert.IsFalse((this.observedDictionary as IDictionary).Contains(24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the GetEnumerator() method of the observable dictionary
|
||||
/// returns a working enumerator if accessed via the IDictionary interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestEnumeratorViaIDictionary() {
|
||||
Dictionary<int, string> outputNumbers = new Dictionary<int, string>();
|
||||
foreach(DictionaryEntry entry in (this.observedDictionary as IDictionary)) {
|
||||
(outputNumbers as IDictionary).Add(entry.Key, entry.Value);
|
||||
}
|
||||
|
||||
CollectionAssert.AreEquivalent(this.observedDictionary, outputNumbers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the IsFixedSize property of the observable dictionary returns
|
||||
/// the expected result for a read only dictionary based on a dynamic dictionary
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestIsFixedSizeViaIList() {
|
||||
Assert.IsFalse((this.observedDictionary as IDictionary).IsFixedSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the keys collection of the observable dictionary can be queried
|
||||
/// via the IDictionary interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetKeysCollectionViaIDictionary() {
|
||||
ICollection keys = (this.observedDictionary as IDictionary).Keys;
|
||||
Assert.AreEqual(this.observedDictionary.Count, keys.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the values collection of the observable dictionary can be queried
|
||||
/// via the IDictionary interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetValuesCollectionViaIDictionary() {
|
||||
ICollection values = (this.observedDictionary as IDictionary).Values;
|
||||
Assert.AreEqual(this.observedDictionary.Count, values.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether Remove() method works via the IDictionary interface
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the retrieval of values using the indexer of the observable
|
||||
/// dictionary is working via the IDictionary interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRetrieveValueByIndexerViaIDictionary() {
|
||||
Assert.AreEqual("forty-two", (this.observedDictionary as IDictionary)[42]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the indexer can be used to insert an item via the IDictionary interface
|
||||
/// </summary>
|
||||
[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]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether Add() method is working via the generic
|
||||
/// ICollection<> interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddViaGenericICollection() {
|
||||
Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
|
||||
(this.observedDictionary as ICollection<KeyValuePair<int, string>>).Add(
|
||||
new KeyValuePair<int, string>(24, "twenty-four")
|
||||
);
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
|
||||
CollectionAssert.Contains(
|
||||
this.observedDictionary, new KeyValuePair<int, string>(24, "twenty-four")
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Clear() method is working via the generic
|
||||
/// ICollection<> interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestClearViaGenericICollection() {
|
||||
Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments();
|
||||
(this.observedDictionary as ICollection<KeyValuePair<int, string>>).Clear();
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
|
||||
Assert.AreEqual(0, this.observedDictionary.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Remove() method is working via the
|
||||
/// generic ICollection<> interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRemoveViaGenericICollection() {
|
||||
IEnumerator<KeyValuePair<int, string>> enumerator =
|
||||
(this.observedDictionary as ICollection<KeyValuePair<int, string>>).GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
|
||||
(this.observedDictionary as ICollection<KeyValuePair<int, string>>).Remove(
|
||||
enumerator.Current
|
||||
);
|
||||
this.mockery.VerifyAllExpectationsHaveBeenMet();
|
||||
|
||||
CollectionAssert.DoesNotContain(this.observedDictionary, enumerator.Current);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the CopyTo() of the observable dictionary works when called
|
||||
/// via the the ICollection interface
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCopyToArrayViaICollection() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
DictionaryEntry[] entries = new DictionaryEntry[numbers.Count];
|
||||
(testDictionary as ICollection).CopyTo(entries, 0);
|
||||
|
||||
KeyValuePair<int, string>[] items = new KeyValuePair<int, string>[numbers.Count];
|
||||
for(int index = 0; index < entries.Length; ++index) {
|
||||
items[index] = new KeyValuePair<int, string>(
|
||||
(int)entries[index].Key, (string)entries[index].Value
|
||||
);
|
||||
}
|
||||
CollectionAssert.AreEquivalent(numbers, items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the IsSynchronized property and the SyncRoot property are working
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSynchronization() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary = makeObservable(numbers);
|
||||
|
||||
if(!(testDictionary as ICollection).IsSynchronized) {
|
||||
lock((testDictionary as ICollection).SyncRoot) {
|
||||
Assert.AreEqual(numbers.Count, testDictionary.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test whether the observable dictionary can be serialized
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSerialization() {
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
|
||||
using(MemoryStream memory = new MemoryStream()) {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ObservableDictionary<int, string> testDictionary1 = makeObservable(numbers);
|
||||
|
||||
formatter.Serialize(memory, testDictionary1);
|
||||
memory.Position = 0;
|
||||
object testDictionary2 = formatter.Deserialize(memory);
|
||||
|
||||
CollectionAssert.AreEquivalent(testDictionary1, (IEnumerable)testDictionary2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new observable dictionary filled with some values for testing
|
||||
/// </summary>
|
||||
/// <returns>The newly created observable dictionary</returns>
|
||||
private static Dictionary<int, string> createTestDictionary() {
|
||||
Dictionary<int, string> numbers = new Dictionary<int, string>();
|
||||
numbers.Add(1, "one");
|
||||
numbers.Add(2, "two");
|
||||
numbers.Add(3, "three");
|
||||
numbers.Add(42, "forty-two");
|
||||
return new Dictionary<int, string>(numbers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new observable dictionary filled with some values for testing
|
||||
/// </summary>
|
||||
/// <returns>The newly created observable dictionary</returns>
|
||||
private static ObservableDictionary<int, string> makeObservable(
|
||||
IDictionary<int, string> dictionary
|
||||
) {
|
||||
return new ObservableDictionary<int, string>(dictionary);
|
||||
}
|
||||
|
||||
/// <summary>Mock object factory</summary>
|
||||
private Mockery mockery;
|
||||
/// <summary>The mocked observable collection subscriber</summary>
|
||||
private IObservableDictionarySubscriber mockedSubscriber;
|
||||
/// <summary>An observable dictionary to which a mock will be subscribed</summary>
|
||||
private ObservableDictionary<int, string> observedDictionary;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Collections
|
||||
|
||||
#endif // UNITTEST
|
405
Source/Collections/ObservableDictionary.cs
Normal file
405
Source/Collections/ObservableDictionary.cs
Normal file
|
@ -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 {
|
||||
|
||||
/// <summary>A dictionary that sneds out change notifications</summary>
|
||||
/// <typeparam name="KeyType">Type of the keys used in the dictionary</typeparam>
|
||||
/// <typeparam name="ValueType">Type of the values used in the dictionary</typeparam>
|
||||
[Serializable]
|
||||
public class ObservableDictionary<KeyType, ValueType> :
|
||||
#if !COMPACTFRAMEWORK
|
||||
ISerializable,
|
||||
IDeserializationCallback,
|
||||
#endif
|
||||
IDictionary<KeyType, ValueType>,
|
||||
IDictionary {
|
||||
|
||||
#if !COMPACTFRAMEWORK
|
||||
#region class SerializedDictionary
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary wrapped used to reconstruct a serialized read only dictionary
|
||||
/// </summary>
|
||||
private class SerializedDictionary : Dictionary<KeyType, ValueType> {
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the System.WeakReference class, using deserialized
|
||||
/// data from the specified serialization and stream objects.
|
||||
/// </summary>
|
||||
/// <param name="info">
|
||||
/// An object that holds all the data needed to serialize or deserialize the
|
||||
/// current System.WeakReference object.
|
||||
/// </param>
|
||||
/// <param name="context">
|
||||
/// (Reserved) Describes the source and destination of the serialized stream
|
||||
/// specified by info.
|
||||
/// </param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// The info parameter is null.
|
||||
/// </exception>
|
||||
public SerializedDictionary(SerializationInfo info, StreamingContext context) :
|
||||
base(info, context) { }
|
||||
|
||||
}
|
||||
|
||||
#endregion // class SerializeDictionary
|
||||
#endif // !COMPACTFRAMEWORK
|
||||
|
||||
/// <summary>Raised when an item has been added to the dictionary</summary>
|
||||
public event EventHandler<ItemEventArgs<KeyValuePair<KeyType, ValueType>>> ItemAdded;
|
||||
/// <summary>Raised when an item is removed from the dictionary</summary>
|
||||
public event EventHandler<ItemEventArgs<KeyValuePair<KeyType, ValueType>>> ItemRemoved;
|
||||
/// <summary>Raised when the dictionary is about to be cleared</summary>
|
||||
public event EventHandler Clearing;
|
||||
|
||||
/// <summary>Initializes a new observable dictionary</summary>
|
||||
public ObservableDictionary() : this(new Dictionary<KeyType, ValueType>()) { }
|
||||
|
||||
/// <summary>Initializes a new observable Dictionary wrapper</summary>
|
||||
/// <param name="dictionary">Dictionary that will be wrapped</param>
|
||||
public ObservableDictionary(IDictionary<KeyType, ValueType> dictionary) {
|
||||
this.typedDictionary = dictionary;
|
||||
this.objectDictionary = (this.typedDictionary as IDictionary);
|
||||
}
|
||||
|
||||
#if !COMPACTFRAMEWORK
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the System.WeakReference class, using deserialized
|
||||
/// data from the specified serialization and stream objects.
|
||||
/// </summary>
|
||||
/// <param name="info">
|
||||
/// An object that holds all the data needed to serialize or deserialize the
|
||||
/// current System.WeakReference object.
|
||||
/// </param>
|
||||
/// <param name="context">
|
||||
/// (Reserved) Describes the source and destination of the serialized stream
|
||||
/// specified by info.
|
||||
/// </param>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// The info parameter is null.
|
||||
/// </exception>
|
||||
protected ObservableDictionary(SerializationInfo info, StreamingContext context) :
|
||||
this(new SerializedDictionary(info, context)) { }
|
||||
#endif // !COMPACTFRAMEWORK
|
||||
|
||||
/// <summary>Whether the directory is write-protected</summary>
|
||||
public bool IsReadOnly {
|
||||
get { return this.typedDictionary.IsReadOnly; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified KeyValuePair is contained in the Dictionary
|
||||
/// </summary>
|
||||
/// <param name="item">KeyValuePair that will be checked for</param>
|
||||
/// <returns>True if the provided KeyValuePair was contained in the Dictionary</returns>
|
||||
public bool Contains(KeyValuePair<KeyType, ValueType> item) {
|
||||
return this.typedDictionary.Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the Dictionary contains the specified key</summary>
|
||||
/// <param name="key">Key that will be checked for</param>
|
||||
/// <returns>
|
||||
/// True if an entry with the specified key was contained in the Dictionary
|
||||
/// </returns>
|
||||
public bool ContainsKey(KeyType key) {
|
||||
return this.typedDictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>Copies the contents of the Dictionary into an array</summary>
|
||||
/// <param name="array">Array the Dictionary will be copied into</param>
|
||||
/// <param name="arrayIndex">
|
||||
/// Starting index at which to begin filling the destination array
|
||||
/// </param>
|
||||
public void CopyTo(KeyValuePair<KeyType, ValueType>[] array, int arrayIndex) {
|
||||
this.typedDictionary.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>Number of elements contained in the Dictionary</summary>
|
||||
public int Count {
|
||||
get { return this.typedDictionary.Count; }
|
||||
}
|
||||
|
||||
/// <summary>Creates a new enumerator for the Dictionary</summary>
|
||||
/// <returns>The new Dictionary enumerator</returns>
|
||||
public IEnumerator<KeyValuePair<KeyType, ValueType>> GetEnumerator() {
|
||||
return this.typedDictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>Collection of all keys contained in the Dictionary</summary>
|
||||
public ICollection<KeyType> Keys {
|
||||
get { return this.typedDictionary.Keys; }
|
||||
}
|
||||
|
||||
/// <summary>Collection of all values contained in the Dictionary</summary>
|
||||
public ICollection<ValueType> Values {
|
||||
get { return this.typedDictionary.Values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve the item with the specified key from the Dictionary
|
||||
/// </summary>
|
||||
/// <param name="key">Key of the item to attempt to retrieve</param>
|
||||
/// <param name="value">
|
||||
/// Output parameter that will receive the key upon successful completion
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if the item was found and has been placed in the output parameter
|
||||
/// </returns>
|
||||
public bool TryGetValue(KeyType key, out ValueType value) {
|
||||
return this.typedDictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <summary>Accesses an item in the Dictionary by its key</summary>
|
||||
/// <param name="key">Key of the item that will be accessed</param>
|
||||
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<KeyType, ValueType>(key, oldValue));
|
||||
}
|
||||
OnAdded(new KeyValuePair<KeyType, ValueType>(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Inserts an item into the Dictionary</summary>
|
||||
/// <param name="key">Key under which to add the new item</param>
|
||||
/// <param name="value">Item that will be added to the Dictionary</param>
|
||||
public void Add(KeyType key, ValueType value) {
|
||||
this.typedDictionary.Add(key, value);
|
||||
OnAdded(new KeyValuePair<KeyType, ValueType>(key, value));
|
||||
}
|
||||
|
||||
/// <summary>Removes the item with the specified key from the Dictionary</summary>
|
||||
/// <param name="key">Key of the elementes that will be removed</param>
|
||||
/// <returns>True if an item with the specified key was found and removed</returns>
|
||||
public bool Remove(KeyType key) {
|
||||
ValueType oldValue;
|
||||
this.typedDictionary.TryGetValue(key, out oldValue);
|
||||
|
||||
bool removed = this.typedDictionary.Remove(key);
|
||||
if(removed) {
|
||||
OnRemoved(new KeyValuePair<KeyType, ValueType>(key, oldValue));
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/// <summary>Removes all items from the Dictionary</summary>
|
||||
public void Clear() {
|
||||
OnClearing();
|
||||
this.typedDictionary.Clear();
|
||||
}
|
||||
|
||||
/// <summary>Fires the 'ItemAdded' event</summary>
|
||||
/// <param name="item">Item that has been added to the collection</param>
|
||||
protected virtual void OnAdded(KeyValuePair<KeyType, ValueType> item) {
|
||||
if(ItemAdded != null)
|
||||
ItemAdded(this, new ItemEventArgs<KeyValuePair<KeyType, ValueType>>(item));
|
||||
}
|
||||
|
||||
/// <summary>Fires the 'ItemRemoved' event</summary>
|
||||
/// <param name="item">Item that has been removed from the collection</param>
|
||||
protected virtual void OnRemoved(KeyValuePair<KeyType, ValueType> item) {
|
||||
if(ItemRemoved != null)
|
||||
ItemRemoved(this, new ItemEventArgs<KeyValuePair<KeyType, ValueType>>(item));
|
||||
}
|
||||
|
||||
/// <summary>Fires the 'Clearing' event</summary>
|
||||
protected virtual void OnClearing() {
|
||||
if(Clearing != null)
|
||||
Clearing(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#region IEnumerable implementation
|
||||
|
||||
/// <summary>Returns a new object enumerator for the Dictionary</summary>
|
||||
/// <returns>The new object enumerator</returns>
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
|
||||
return (this.typedDictionary as IEnumerable).GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDictionary implementation
|
||||
|
||||
/// <summary>Adds an item into the Dictionary</summary>
|
||||
/// <param name="key">Key under which the item will be added</param>
|
||||
/// <param name="value">Item that will be added</param>
|
||||
void IDictionary.Add(object key, object value) {
|
||||
this.objectDictionary.Add(key, value);
|
||||
OnAdded(new KeyValuePair<KeyType, ValueType>((KeyType)key, (ValueType)value));
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the specified key exists in the Dictionary</summary>
|
||||
/// <param name="key">Key that will be checked for</param>
|
||||
/// <returns>True if an item with the specified key exists in the Dictionary</returns>
|
||||
bool IDictionary.Contains(object key) {
|
||||
return this.objectDictionary.Contains(key);
|
||||
}
|
||||
|
||||
/// <summary>Returns a new entry enumerator for the dictionary</summary>
|
||||
/// <returns>The new entry enumerator</returns>
|
||||
IDictionaryEnumerator IDictionary.GetEnumerator() {
|
||||
return this.objectDictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>Whether the size of the Dictionary is fixed</summary>
|
||||
bool IDictionary.IsFixedSize {
|
||||
get { return this.objectDictionary.IsFixedSize; }
|
||||
}
|
||||
|
||||
/// <summary>Returns a collection of all keys in the Dictionary</summary>
|
||||
ICollection IDictionary.Keys {
|
||||
get { return this.objectDictionary.Keys; }
|
||||
}
|
||||
|
||||
/// <summary>Returns a collection of all values stored in the Dictionary</summary>
|
||||
ICollection IDictionary.Values {
|
||||
get { return this.objectDictionary.Values; }
|
||||
}
|
||||
|
||||
/// <summary>Removes an item from the Dictionary</summary>
|
||||
/// <param name="key">Key of the item that will be removed</param>
|
||||
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, ValueType>((KeyType)key, (ValueType)value));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Accesses an item in the Dictionary by its key</summary>
|
||||
/// <param name="key">Key of the item that will be accessed</param>
|
||||
/// <returns>The item with the specified key</returns>
|
||||
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, ValueType>((KeyType)key, oldValue));
|
||||
}
|
||||
OnAdded(new KeyValuePair<KeyType, ValueType>((KeyType)key, (ValueType)value));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICollection<> implementation
|
||||
|
||||
/// <summary>Inserts an already prepared element into the Dictionary</summary>
|
||||
/// <param name="item">Prepared element that will be added to the Dictionary</param>
|
||||
void ICollection<KeyValuePair<KeyType, ValueType>>.Add(
|
||||
KeyValuePair<KeyType, ValueType> item
|
||||
) {
|
||||
this.typedDictionary.Add(item);
|
||||
OnAdded(item);
|
||||
}
|
||||
|
||||
/// <summary>Removes all items from the Dictionary</summary>
|
||||
void ICollection<KeyValuePair<KeyType, ValueType>>.Clear() {
|
||||
OnClearing();
|
||||
this.typedDictionary.Clear();
|
||||
}
|
||||
|
||||
/// <summary>Removes all items from the Dictionary</summary>
|
||||
/// <param name="itemToRemove">Item that will be removed from the Dictionary</param>
|
||||
bool ICollection<KeyValuePair<KeyType, ValueType>>.Remove(
|
||||
KeyValuePair<KeyType, ValueType> itemToRemove
|
||||
) {
|
||||
bool removed = this.typedDictionary.Remove(itemToRemove);
|
||||
if(removed) {
|
||||
OnRemoved(itemToRemove);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICollection implementation
|
||||
|
||||
/// <summary>Copies the contents of the Dictionary into an array</summary>
|
||||
/// <param name="array">Array the Dictionary contents will be copied into</param>
|
||||
/// <param name="index">
|
||||
/// Starting index at which to begin filling the destination array
|
||||
/// </param>
|
||||
void ICollection.CopyTo(Array array, int index) {
|
||||
this.objectDictionary.CopyTo(array, index);
|
||||
}
|
||||
|
||||
/// <summary>Whether the Dictionary is synchronized for multi-threaded usage</summary>
|
||||
bool ICollection.IsSynchronized {
|
||||
get { return this.objectDictionary.IsSynchronized; }
|
||||
}
|
||||
|
||||
/// <summary>Synchronization root on which the Dictionary locks</summary>
|
||||
object ICollection.SyncRoot {
|
||||
get { return this.objectDictionary.SyncRoot; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#if !COMPACTFRAMEWORK
|
||||
#region ISerializable implementation
|
||||
|
||||
/// <summary>Serializes the Dictionary</summary>
|
||||
/// <param name="info">
|
||||
/// Provides the container into which the Dictionary will serialize itself
|
||||
/// </param>
|
||||
/// <param name="context">
|
||||
/// Contextual informations about the serialization environment
|
||||
/// </param>
|
||||
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
|
||||
(this.typedDictionary as ISerializable).GetObjectData(info, context);
|
||||
}
|
||||
|
||||
/// <summary>Called after all objects have been successfully deserialized</summary>
|
||||
/// <param name="sender">Nicht unterstützt</param>
|
||||
void IDeserializationCallback.OnDeserialization(object sender) {
|
||||
(this.typedDictionary as IDeserializationCallback).OnDeserialization(sender);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endif //!COMPACTFRAMEWORK
|
||||
|
||||
/// <summary>The wrapped Dictionary under its type-safe interface</summary>
|
||||
private IDictionary<KeyType, ValueType> typedDictionary;
|
||||
/// <summary>The wrapped Dictionary under its object interface</summary>
|
||||
private IDictionary objectDictionary;
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Collections
|
|
@ -188,7 +188,7 @@ namespace Nuclex.Support.Collections {
|
|||
/// Add() method is called via the generic IDictionary<> interface
|
||||
/// </summary>
|
||||
[Test, ExpectedException(typeof(NotSupportedException))]
|
||||
public void TestThrowOnAddAtViaGenericIDictionary() {
|
||||
public void TestThrowOnAddViaGenericIDictionary() {
|
||||
Dictionary<int, string> numbers = createTestDictionary();
|
||||
ReadOnlyDictionary<int, string> testDictionary = makeReadOnly(numbers);
|
||||
|
||||
|
@ -388,7 +388,7 @@ namespace Nuclex.Support.Collections {
|
|||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
[Test, ExpectedException(typeof(NotSupportedException))]
|
||||
public void TestThrowOnRemoveViaGenericICollection() {
|
||||
|
@ -396,7 +396,7 @@ namespace Nuclex.Support.Collections {
|
|||
ReadOnlyDictionary<int, string> testDictionary = makeReadOnly(numbers);
|
||||
|
||||
(testDictionary as ICollection<KeyValuePair<int, string>>).Remove(
|
||||
new KeyValuePair<int, string>(24, "twenty-four")
|
||||
new KeyValuePair<int, string>(42, "fourty-two")
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,9 @@ using System.Runtime.Serialization;
|
|||
|
||||
namespace Nuclex.Support.Collections {
|
||||
|
||||
/// <summary>Wraps a Dictionary and prevents users from modifying it</summary>
|
||||
/// <typeparam name="KeyType">Type of the keys used in the Dictionary</typeparam>
|
||||
/// <typeparam name="ValueType">Type of the values used in the Dictionary</typeparam>
|
||||
/// <summary>Wraps a dictionary and prevents users from modifying it</summary>
|
||||
/// <typeparam name="KeyType">Type of the keys used in the dictionary</typeparam>
|
||||
/// <typeparam name="ValueType">Type of the values used in the dictionary</typeparam>
|
||||
[Serializable]
|
||||
public class ReadOnlyDictionary<KeyType, ValueType> :
|
||||
#if !COMPACTFRAMEWORK
|
||||
|
@ -89,7 +89,7 @@ namespace Nuclex.Support.Collections {
|
|||
|
||||
#endif // !COMPACTFRAMEWORK
|
||||
|
||||
/// <summary>Initializes a new read-only Dictionary wrapper</summary>
|
||||
/// <summary>Initializes a new read-only dictionary wrapper</summary>
|
||||
/// <param name="dictionary">Dictionary that will be wrapped</param>
|
||||
public ReadOnlyDictionary(IDictionary<KeyType, ValueType> dictionary) {
|
||||
this.typedDictionary = dictionary;
|
||||
|
|
Loading…
Reference in New Issue
Block a user