diff --git a/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableCollection_INotifyCollectionChangedTests.cs b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableCollection_INotifyCollectionChangedTests.cs
new file mode 100644
index 0000000..de42c0b
--- /dev/null
+++ b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableCollection_INotifyCollectionChangedTests.cs
@@ -0,0 +1,192 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Swordfish.NET.Collections;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Text;
+
+namespace Swordfish.NET.UnitTestV3
+{
+ ///
+ /// Tests that the following methods fire the correct event in ConcurrentObservableCollection:
+ ///
+ /// - AddRange
+ /// - InsertRange
+ /// - RemoveRange
+ /// - Reset
+ /// - Clear
+ ///
+ /// Test the following collection classes:
+ ///
+ /// - ConcurrentObservableCollection - done (this class)
+ /// - ConcurrentObservableDictionary
+ /// - ConcurrentObservableHashSet
+ /// - ConcurrentObservableSortedCollection
+ /// - ConcurrentObservableSortedDictionary
+ /// - ConcurrentObservableSortedSet
+ ///
+ [TestClass]
+ public class ConcurrentObservableCollection_INotifyCollectionChangedTests
+ {
+ [TestMethod]
+ public void Test_ConcurrentObservableCollection_AddRange()
+ {
+ var toAdd = Enumerable.Range(0, 100).ToList();
+ var collection = new ConcurrentObservableCollection();
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.AddRange(toAdd);
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add);
+ Assert.IsNotNull(returnedArgs.NewItems);
+ Assert.IsNull(returnedArgs.OldItems);
+ Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count);
+ Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType(), (a, b) => a == b).All(c => c));
+
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableCollection_InsertRange()
+ {
+ var initial = Enumerable.Range(0, 100).ToList();
+ var toAdd = Enumerable.Range(100, 100).ToList();
+ var startIndex = 50;
+ var collection = new ConcurrentObservableCollection();
+ collection.AddRange(initial);
+ Assert.AreEqual(100, collection.Count);
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.InsertRange(startIndex, toAdd);
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(NotifyCollectionChangedAction.Add, returnedArgs.Action);
+ Assert.AreEqual(startIndex, returnedArgs.NewStartingIndex);
+ Assert.IsNotNull(returnedArgs.NewItems);
+ Assert.IsNull(returnedArgs.OldItems);
+ Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count);
+ Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType(), (a, b) => a == b).All(c => c));
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableCollection_RemoveRange()
+ {
+ var initial = Enumerable.Range(0, 100).ToList();
+ var startIndex = 50;
+ var removeCount = 40;
+ var collection = new ConcurrentObservableCollection();
+ collection.AddRange(initial);
+ Assert.AreEqual(100, collection.Count);
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.RemoveRange(startIndex, removeCount);
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.IsNotNull(returnedObject);
+ Assert.IsNotNull(returnedArgs);
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action);
+ Assert.AreEqual(startIndex, returnedArgs.OldStartingIndex);
+ Assert.IsNull(returnedArgs.NewItems);
+ Assert.IsNotNull(returnedArgs.OldItems);
+ Assert.AreEqual(removeCount, returnedArgs.OldItems.Count);
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableCollection_Reset()
+ {
+ var initial = Enumerable.Range(0, 100).ToList();
+ var toAdd = Enumerable.Range(100, 100).ToList();
+ var collection = new ConcurrentObservableCollection();
+ collection.AddRange(initial);
+ Assert.AreEqual(100, collection.Count);
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.Reset(toAdd);
+
+ // Check two collection changed events were fired
+ Assert.AreEqual(2, returnedList.Count);
+ (var returnedObject0, var returnedArgs0) = returnedList[0];
+ (var returnedObject1, var returnedArgs1) = returnedList[1];
+
+ Assert.IsNotNull(returnedObject0);
+ Assert.IsNotNull(returnedArgs0);
+ Assert.IsNotNull(returnedObject1);
+ Assert.IsNotNull(returnedArgs1);
+
+ Assert.AreEqual(returnedObject0, collection);
+ Assert.AreEqual(returnedObject1, collection);
+ Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs0.Action);
+ Assert.AreEqual(NotifyCollectionChangedAction.Add, returnedArgs1.Action);
+
+ Assert.IsNull(returnedArgs0.NewItems);
+ Assert.IsNotNull(returnedArgs0.OldItems);
+ Assert.AreEqual(initial.Count(), returnedArgs0.OldItems.Count);
+ Assert.IsTrue(initial.Zip(returnedArgs0.OldItems.OfType(), (a, b) => a == b).All(c => c));
+
+ Assert.IsNull(returnedArgs1.OldItems);
+ Assert.IsNotNull(returnedArgs1.NewItems);
+ Assert.AreEqual(toAdd.Count(), returnedArgs1.NewItems.Count);
+ Assert.IsTrue(toAdd.Zip(returnedArgs1.NewItems.OfType(), (a, b) => a == b).All(c => c));
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableCollection_Clear()
+ {
+ var initial = Enumerable.Range(0, 100).ToList();
+ var collection = new ConcurrentObservableCollection();
+ collection.AddRange(initial);
+ Assert.AreEqual(100, collection.Count);
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.Clear();
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.IsNotNull(returnedObject);
+ Assert.IsNotNull(returnedArgs);
+
+ Assert.AreEqual(0, collection.Count);
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action);
+
+ Assert.IsNull(returnedArgs.NewItems);
+
+ Assert.IsNotNull(returnedArgs.OldItems);
+ Assert.AreEqual(initial.Count(), returnedArgs.OldItems.Count);
+ Assert.IsTrue(initial.Zip(returnedArgs.OldItems.OfType(), (a, b) => a == b).All(c => c));
+ }
+
+ }
+}
diff --git a/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableDictionary_INotifyCollectionChangedTests.cs b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableDictionary_INotifyCollectionChangedTests.cs
new file mode 100644
index 0000000..dbaba28
--- /dev/null
+++ b/ExamplesAndTests/Swordfish.NET.UnitTestV3/ConcurrentObservableDictionary_INotifyCollectionChangedTests.cs
@@ -0,0 +1,165 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Swordfish.NET.Collections;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace Swordfish.NET.UnitTestV3
+{
+ ///
+ /// Tests that the following methods fire the correct event in ConcurrentObservableDictionary:
+ ///
+ /// - AddRange
+ /// - RemoveRange
+ /// - Clear
+ ///
+ /// Test the following collection classes:
+ ///
+ /// - ConcurrentObservableCollection - done (other class)
+ /// - ConcurrentObservableDictionary
+ /// - ConcurrentObservableHashSet
+ /// - ConcurrentObservableSortedCollection
+ /// - ConcurrentObservableSortedDictionary
+ /// - ConcurrentObservableSortedSet
+ ///
+ [TestClass]
+ public class ConcurrentObservableDictionary_INotifyCollectionChangedTests
+ {
+ [TestMethod]
+ public void Test_ConcurrentObservableDictionary_AddRange_IEnumerable()
+ {
+ var toAdd = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x));
+ var collection = new ConcurrentObservableDictionary();
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.AddRange(toAdd);
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add);
+ Assert.IsNotNull(returnedArgs.NewItems);
+ Assert.IsNull(returnedArgs.OldItems);
+ Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count);
+ Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c));
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableDictionary_AddRange_List()
+ {
+ var toAdd = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x)).ToList();
+ var collection = new ConcurrentObservableDictionary();
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.AddRange(toAdd);
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add);
+ Assert.IsNotNull(returnedArgs.NewItems);
+ Assert.IsNull(returnedArgs.OldItems);
+ Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count);
+ Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c));
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableDictionary_AddRange_Dictionary()
+ {
+ var toAdd = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x)).ToDictionary(x => x.Key, x => x.Value);
+ var collection = new ConcurrentObservableDictionary();
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.AddRange(toAdd);
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(returnedArgs.Action, NotifyCollectionChangedAction.Add);
+ Assert.IsNotNull(returnedArgs.NewItems);
+ Assert.IsNull(returnedArgs.OldItems);
+ Assert.AreEqual(toAdd.Count(), returnedArgs.NewItems.Count);
+ Assert.IsTrue(toAdd.Zip(returnedArgs.NewItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c));
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableCollection_RemoveRange_ByIndex()
+ {
+ var initial = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x));
+ var startIndex = 50;
+ var removeCount = 40;
+ var collection = new ConcurrentObservableDictionary();
+ collection.AddRange(initial);
+ Assert.AreEqual(100, collection.Count);
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.RemoveRange(startIndex, removeCount);
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.IsNotNull(returnedObject);
+ Assert.IsNotNull(returnedArgs);
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action);
+ Assert.AreEqual(startIndex, returnedArgs.OldStartingIndex);
+ Assert.IsNull(returnedArgs.NewItems);
+ Assert.IsNotNull(returnedArgs.OldItems);
+ Assert.AreEqual(removeCount, returnedArgs.OldItems.Count);
+ }
+
+ [TestMethod]
+ public void Test_ConcurrentObservableDictionary_Clear()
+ {
+ var initial = Enumerable.Range(0, 100).Select(x => new KeyValuePair(x, x));
+ var collection = new ConcurrentObservableDictionary();
+ collection.AddRange(initial);
+ Assert.AreEqual(100, collection.Count);
+
+ // Record all the collection changed events
+ List<(object, NotifyCollectionChangedEventArgs)> returnedList = new List<(object, NotifyCollectionChangedEventArgs)>();
+ collection.CollectionChanged += (s, e) => returnedList.Add((s, e));
+
+ collection.Clear();
+
+ // Check just one collection changed event was fired
+ Assert.AreEqual(1, returnedList.Count);
+ (var returnedObject, var returnedArgs) = returnedList[0];
+
+ Assert.AreEqual(0, collection.Count);
+
+ Assert.AreEqual(returnedObject, collection);
+ Assert.AreEqual(NotifyCollectionChangedAction.Remove, returnedArgs.Action);
+
+ Assert.IsNull(returnedArgs.NewItems);
+
+ Assert.IsNotNull(returnedArgs.OldItems);
+ Assert.AreEqual(initial.Count(), returnedArgs.OldItems.Count);
+ Assert.IsTrue(initial.Zip(returnedArgs.OldItems.OfType>(), (a, b) => a.Key == b.Key && a.Value == b.Value).All(c => c));
+
+ }
+ }
+}
diff --git a/Swordfish.NET.CollectionsV3/ListSelect.cs b/Swordfish.NET.CollectionsV3/ListSelect.cs
index 0163671..2fcacd4 100644
--- a/Swordfish.NET.CollectionsV3/ListSelect.cs
+++ b/Swordfish.NET.CollectionsV3/ListSelect.cs
@@ -18,7 +18,7 @@ public static ListSelect Create(IList
/// Provides an IList interface that lets you use a list with a select to type convert a list as its being accessed
///
- public class ListSelect : IList
+ public class ListSelect : IList, IList
{
private IList _sourceList;
private Func _select;
@@ -51,13 +51,19 @@ int ICollection.Count
}
}
- bool ICollection.IsReadOnly
- {
- get
- {
- return true;
- }
- }
+ bool ICollection.IsReadOnly => true;
+
+ bool IList.IsFixedSize => true;
+
+ bool IList.IsReadOnly => true;
+
+ int ICollection.Count => _sourceList.Count;
+
+ bool ICollection.IsSynchronized => false;
+
+ object ICollection.SyncRoot => null;
+
+ object IList.this[int index] { get => _sourceList[index]; set => throw new NotImplementedException(); }
public void Add(TResult item)
{
@@ -122,5 +128,34 @@ void IList.RemoveAt(int index)
{
throw new NotImplementedException();
}
+
+ int IList.Add(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ bool IList.Contains(object value) => Contains((TResult)value);
+
+ int IList.IndexOf(object value) => IndexOf((TResult)value);
+
+ void IList.Insert(int index, object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ void IList.Remove(object value)
+ {
+ throw new NotImplementedException();
+ }
+
+ void IList.RemoveAt(int index)
+ {
+ throw new NotImplementedException();
+ }
+
+ void ICollection.CopyTo(Array array, int index)
+ {
+ throw new NotImplementedException();
+ }
}
}