diff --git a/sandbox/BlazorApp/BlazorApp.csproj b/sandbox/BlazorApp/BlazorApp.csproj
index e948168..e5eafff 100644
--- a/sandbox/BlazorApp/BlazorApp.csproj
+++ b/sandbox/BlazorApp/BlazorApp.csproj
@@ -4,4 +4,8 @@
net6.0
+
+
+
+
diff --git a/sandbox/BlazorApp/Pages/Index.razor b/sandbox/BlazorApp/Pages/Index.razor
index e54d914..1a6f6f4 100644
--- a/sandbox/BlazorApp/Pages/Index.razor
+++ b/sandbox/BlazorApp/Pages/Index.razor
@@ -1,7 +1,12 @@
@page "/"
-
Hello, world!
+
-Welcome to your new app.
-
-
+
+ @foreach (var item in ItemsView)
+ {
+
+ @item |
+
+ }
+
\ No newline at end of file
diff --git a/sandbox/BlazorApp/Pages/Index.razor.cs b/sandbox/BlazorApp/Pages/Index.razor.cs
index c8a0fc1..45a68e3 100644
--- a/sandbox/BlazorApp/Pages/Index.razor.cs
+++ b/sandbox/BlazorApp/Pages/Index.razor.cs
@@ -1,9 +1,40 @@
using Microsoft.AspNetCore.Components;
+using ObservableCollections;
namespace BlazorApp.Pages;
public partial class Index
{
+ ObservableList list;
+ public ISynchronizedView ItemsView { get; set; }
+ int adder = 99;
+ RenderFragment fragment;
+
+ protected override void OnInitialized()
+ {
+ list = new ObservableList();
+ list.AddRange(new[] { 1, 10, 188 });
+ ItemsView = list.CreateSortedView(x => x, x => x, comparer: Comparer.Default).WithINotifyCollectionChanged();
+
+
+ fragment = builder =>
+ {
+ builder.GetFrames();
+
+ };
+ }
+
+
+
+ void OnClick()
+ {
+ ThreadPool.QueueUserWorkItem(_ =>
+ {
+ list.Add(adder++);
+
+ _ = InvokeAsync(StateHasChanged);
+ });
+ }
}
diff --git a/sandbox/WpfApp/MainWindow.xaml.cs b/sandbox/WpfApp/MainWindow.xaml.cs
index 38ab9bf..835e88d 100644
--- a/sandbox/WpfApp/MainWindow.xaml.cs
+++ b/sandbox/WpfApp/MainWindow.xaml.cs
@@ -30,7 +30,7 @@ namespace WpfApp
InitializeComponent();
this.DataContext = this;
-
+
list = new ObservableList();
diff --git a/src/ObservableCollections/FreezedDictionary.cs b/src/ObservableCollections/FreezedDictionary.cs
index 4a80455..c973850 100644
--- a/src/ObservableCollections/FreezedDictionary.cs
+++ b/src/ObservableCollections/FreezedDictionary.cs
@@ -1,4 +1,6 @@
-using ObservableCollections.Internal;
+#nullable disable
+
+using ObservableCollections.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
diff --git a/src/ObservableCollections/IObservableCollection.cs b/src/ObservableCollections/IObservableCollection.cs
index d382fc8..ef21cac 100644
--- a/src/ObservableCollections/IObservableCollection.cs
+++ b/src/ObservableCollections/IObservableCollection.cs
@@ -1,4 +1,6 @@
using ObservableCollections.Internal;
+using System;
+using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
diff --git a/src/ObservableCollections/Internal/CloneCollection.cs b/src/ObservableCollections/Internal/CloneCollection.cs
index 7bfadc9..4e9268e 100644
--- a/src/ObservableCollections/Internal/CloneCollection.cs
+++ b/src/ObservableCollections/Internal/CloneCollection.cs
@@ -1,5 +1,7 @@
-using System.Buffers;
+using System;
+using System.Buffers;
using System.Collections;
+using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace ObservableCollections.Internal
@@ -24,7 +26,7 @@ namespace ObservableCollections.Internal
public CloneCollection(IEnumerable source)
{
- if (Enumerable.TryGetNonEnumeratedCount(source, out var count))
+ if (source.TryGetNonEnumeratedCount(out var count))
{
var array = ArrayPool.Shared.Rent(count);
@@ -70,7 +72,7 @@ namespace ObservableCollections.Internal
{
if (array.Length == index)
{
- ArrayPool.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences());
+ ArrayPool.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences());
}
array = ArrayPool.Shared.Rent(index * 2);
}
@@ -79,7 +81,7 @@ namespace ObservableCollections.Internal
{
if (array != null)
{
- ArrayPool.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences());
+ ArrayPool.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences());
array = null;
}
}
diff --git a/src/ObservableCollections/Internal/ResizableArray.cs b/src/ObservableCollections/Internal/ResizableArray.cs
index c520fab..a999db0 100644
--- a/src/ObservableCollections/Internal/ResizableArray.cs
+++ b/src/ObservableCollections/Internal/ResizableArray.cs
@@ -1,4 +1,5 @@
-using System.Buffers;
+using System;
+using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@@ -32,7 +33,7 @@ namespace ObservableCollections.Internal
void EnsureCapacity()
{
var newArray = array.AsSpan().ToArray();
- ArrayPool.Shared.Return(array!, RuntimeHelpers.IsReferenceOrContainsReferences());
+ ArrayPool.Shared.Return(array!, RuntimeHelpersEx.IsReferenceOrContainsReferences());
array = newArray;
}
@@ -40,7 +41,7 @@ namespace ObservableCollections.Internal
{
if (array != null)
{
- ArrayPool.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences());
+ ArrayPool.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences());
array = null;
}
}
diff --git a/src/ObservableCollections/Internal/SortedView.cs b/src/ObservableCollections/Internal/SortedView.cs
index 7dec6d8..7aaa6c8 100644
--- a/src/ObservableCollections/Internal/SortedView.cs
+++ b/src/ObservableCollections/Internal/SortedView.cs
@@ -1,5 +1,8 @@
-using System.Collections;
+using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Linq;
namespace ObservableCollections.Internal
{
diff --git a/src/ObservableCollections/Internal/SortedViewViewComparer.cs b/src/ObservableCollections/Internal/SortedViewViewComparer.cs
index b479017..b8aad3e 100644
--- a/src/ObservableCollections/Internal/SortedViewViewComparer.cs
+++ b/src/ObservableCollections/Internal/SortedViewViewComparer.cs
@@ -1,5 +1,8 @@
-using System.Collections;
+using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Linq;
namespace ObservableCollections.Internal
{
diff --git a/src/ObservableCollections/ObservableCollections.csproj b/src/ObservableCollections/ObservableCollections.csproj
index 58ef59a..496abf6 100644
--- a/src/ObservableCollections/ObservableCollections.csproj
+++ b/src/ObservableCollections/ObservableCollections.csproj
@@ -1,8 +1,13 @@
- net6.0
+ netstandard2.0;netstandard2.1;net5.0;net6.0
enable
+ 10.0
+
+
+
+
diff --git a/src/ObservableCollections/ObservableDictionary.Views.cs b/src/ObservableCollections/ObservableDictionary.Views.cs
index 256fe08..2bee71e 100644
--- a/src/ObservableCollections/ObservableDictionary.Views.cs
+++ b/src/ObservableCollections/ObservableDictionary.Views.cs
@@ -1,6 +1,9 @@
using ObservableCollections.Internal;
+using System;
using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Linq;
namespace ObservableCollections
{
diff --git a/src/ObservableCollections/ObservableDictionary.cs b/src/ObservableCollections/ObservableDictionary.cs
index 891988e..964d731 100644
--- a/src/ObservableCollections/ObservableDictionary.cs
+++ b/src/ObservableCollections/ObservableDictionary.cs
@@ -20,7 +20,15 @@ namespace ObservableCollections
public ObservableDictionary(IEnumerable> collection)
{
+#if NET6_0_OR_GREATER
this.dictionary = new Dictionary(collection);
+#else
+ this.dictionary = new Dictionary();
+ foreach (var item in collection)
+ {
+ dictionary.Add(item.Key, item.Value);
+ }
+#endif
}
public event NotifyCollectionChangedEventHandler>? CollectionChanged;
@@ -191,7 +199,9 @@ namespace ObservableCollections
}
}
+#pragma warning disable CS8767
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
+#pragma warning restore CS8767
{
lock (SyncRoot)
{
diff --git a/src/ObservableCollections/ObservableFixedSizeRingBuffer.cs b/src/ObservableCollections/ObservableFixedSizeRingBuffer.cs
index a450564..d67a11c 100644
--- a/src/ObservableCollections/ObservableFixedSizeRingBuffer.cs
+++ b/src/ObservableCollections/ObservableFixedSizeRingBuffer.cs
@@ -1,5 +1,7 @@
using ObservableCollections.Internal;
+using System;
using System.Collections;
+using System.Collections.Generic;
namespace ObservableCollections
{
diff --git a/src/ObservableCollections/ObservableHashSet.Views.cs b/src/ObservableCollections/ObservableHashSet.Views.cs
index d362841..49450af 100644
--- a/src/ObservableCollections/ObservableHashSet.Views.cs
+++ b/src/ObservableCollections/ObservableHashSet.Views.cs
@@ -1,6 +1,9 @@
using ObservableCollections.Internal;
using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
+using System;
+using System.Linq;
namespace ObservableCollections
{
diff --git a/src/ObservableCollections/ObservableHashSet.cs b/src/ObservableCollections/ObservableHashSet.cs
index 736c6be..3183f0c 100644
--- a/src/ObservableCollections/ObservableHashSet.cs
+++ b/src/ObservableCollections/ObservableHashSet.cs
@@ -1,5 +1,7 @@
using ObservableCollections.Internal;
+using System;
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace ObservableCollections
@@ -16,11 +18,15 @@ namespace ObservableCollections
this.set = new HashSet();
}
+#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
+
public ObservableHashSet(int capacity)
{
this.set = new HashSet(capacity);
}
+#endif
+
public ObservableHashSet(IEnumerable collection)
{
this.set = new HashSet(collection);
@@ -174,11 +180,15 @@ namespace ObservableCollections
}
}
+#if !NETSTANDARD2_0
+
public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue)
{
return set.TryGetValue(equalValue, out actualValue);
}
+#endif
+
public bool Contains(T item)
{
lock (SyncRoot)
diff --git a/src/ObservableCollections/ObservableList.Views.cs b/src/ObservableCollections/ObservableList.Views.cs
index 49e463c..0a503b6 100644
--- a/src/ObservableCollections/ObservableList.Views.cs
+++ b/src/ObservableCollections/ObservableList.Views.cs
@@ -1,6 +1,9 @@
using ObservableCollections.Internal;
+using System;
using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Linq;
namespace ObservableCollections
{
diff --git a/src/ObservableCollections/ObservableList.cs b/src/ObservableCollections/ObservableList.cs
index 92ac0f8..f611db3 100644
--- a/src/ObservableCollections/ObservableList.cs
+++ b/src/ObservableCollections/ObservableList.cs
@@ -102,7 +102,6 @@ namespace ObservableCollections
lock (SyncRoot)
{
var index = list.Count;
- list.EnsureCapacity(items.Length);
foreach (var item in items)
{
list.Add(item);
@@ -242,7 +241,11 @@ namespace ObservableCollections
{
lock (SyncRoot)
{
+#if NET5_0_OR_GREATER
var range = CollectionsMarshal.AsSpan(list).Slice(index, count);
+#else
+ var range = list.GetRange(index, count);
+#endif
// require copy before remove
using (var xs = new CloneCollection(range))
diff --git a/src/ObservableCollections/ObservableQueue.Views.cs b/src/ObservableCollections/ObservableQueue.Views.cs
index dc2ef59..82fc720 100644
--- a/src/ObservableCollections/ObservableQueue.Views.cs
+++ b/src/ObservableCollections/ObservableQueue.Views.cs
@@ -1,6 +1,9 @@
using ObservableCollections.Internal;
using System.Collections;
using System.Collections.Specialized;
+using System;
+using System.Collections.Generic;
+using System.Linq;
namespace ObservableCollections
{
@@ -120,7 +123,6 @@ namespace ObservableCollections
}
else
{
- queue.EnsureCapacity(e.NewItems.Length);
foreach (var item in e.NewItems)
{
var v = (item, selector(item));
diff --git a/src/ObservableCollections/ObservableQueue.cs b/src/ObservableCollections/ObservableQueue.cs
index 6696a6a..7de4d5f 100644
--- a/src/ObservableCollections/ObservableQueue.cs
+++ b/src/ObservableCollections/ObservableQueue.cs
@@ -3,6 +3,10 @@ using System.Buffers;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
namespace ObservableCollections
{
@@ -105,11 +109,13 @@ namespace ObservableCollections
{
lock (SyncRoot)
{
- if (queue.TryDequeue(out result))
+ if (queue.Count != 0)
{
+ result = queue.Dequeue();
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs.Remove(result, 0));
return true;
}
+ result = default;
return false;
}
}
@@ -130,7 +136,7 @@ namespace ObservableCollections
}
finally
{
- ArrayPool.Shared.Return(dest, RuntimeHelpers.IsReferenceOrContainsReferences());
+ ArrayPool.Shared.Return(dest, RuntimeHelpersEx.IsReferenceOrContainsReferences());
}
}
}
@@ -169,7 +175,13 @@ namespace ObservableCollections
{
lock (SyncRoot)
{
- return queue.TryPeek(out result);
+ if (queue.Count != 0)
+ {
+ result = queue.Peek();
+ return true;
+ }
+ result = default;
+ return false;
}
}
@@ -189,14 +201,6 @@ namespace ObservableCollections
}
}
- public void EnsureCapacity(int capacity)
- {
- lock (SyncRoot)
- {
- queue.EnsureCapacity(capacity);
- }
- }
-
public IEnumerator GetEnumerator()
{
return new SynchronizedEnumerator(SyncRoot, queue.GetEnumerator());
diff --git a/src/ObservableCollections/ObservableRingBuffer.Views.cs b/src/ObservableCollections/ObservableRingBuffer.Views.cs
index aa7fc94..50df81e 100644
--- a/src/ObservableCollections/ObservableRingBuffer.Views.cs
+++ b/src/ObservableCollections/ObservableRingBuffer.Views.cs
@@ -1,6 +1,9 @@
using ObservableCollections.Internal;
+using System;
using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Linq;
namespace ObservableCollections
{
diff --git a/src/ObservableCollections/ObservableRingBuffer.cs b/src/ObservableCollections/ObservableRingBuffer.cs
index c59ab83..0f653e3 100644
--- a/src/ObservableCollections/ObservableRingBuffer.cs
+++ b/src/ObservableCollections/ObservableRingBuffer.cs
@@ -1,4 +1,7 @@
using ObservableCollections.Internal;
+using System;
+using System.Linq;
+using System.Collections.Generic;
using System.Collections;
namespace ObservableCollections
diff --git a/src/ObservableCollections/ObservableStack.Views.cs b/src/ObservableCollections/ObservableStack.Views.cs
index 3a3d4ef..81cbf97 100644
--- a/src/ObservableCollections/ObservableStack.Views.cs
+++ b/src/ObservableCollections/ObservableStack.Views.cs
@@ -1,6 +1,9 @@
using ObservableCollections.Internal;
+using System;
using System.Collections;
+using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Linq;
namespace ObservableCollections
{
@@ -120,7 +123,6 @@ namespace ObservableCollections
}
else
{
- stack.EnsureCapacity(e.NewItems.Length);
foreach (var item in e.NewItems)
{
var v = (item, selector(item));
diff --git a/src/ObservableCollections/ObservableStack.cs b/src/ObservableCollections/ObservableStack.cs
index 2de5999..e1d56e7 100644
--- a/src/ObservableCollections/ObservableStack.cs
+++ b/src/ObservableCollections/ObservableStack.cs
@@ -1,6 +1,8 @@
using ObservableCollections.Internal;
+using System;
using System.Buffers;
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@@ -102,11 +104,14 @@ namespace ObservableCollections
{
lock (SyncRoot)
{
- if (stack.TryPop(out result))
+ if (stack.Count != 0)
{
+ result = stack.Pop();
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs.Remove(result, 0));
return true;
}
+
+ result = default;
return false;
}
}
@@ -127,7 +132,7 @@ namespace ObservableCollections
}
finally
{
- ArrayPool.Shared.Return(dest, RuntimeHelpers.IsReferenceOrContainsReferences());
+ ArrayPool.Shared.Return(dest, RuntimeHelpersEx.IsReferenceOrContainsReferences());
}
}
}
@@ -166,7 +171,13 @@ namespace ObservableCollections
{
lock (SyncRoot)
{
- return stack.TryPeek(out result);
+ if (stack.Count != 0)
+ {
+ result = stack.Peek();
+ return true;
+ }
+ result = default;
+ return false;
}
}
@@ -186,14 +197,6 @@ namespace ObservableCollections
}
}
- public void EnsureCapacity(int capacity)
- {
- lock (SyncRoot)
- {
- stack.EnsureCapacity(capacity);
- }
- }
-
public IEnumerator GetEnumerator()
{
return new SynchronizedEnumerator(SyncRoot, stack.GetEnumerator());
diff --git a/src/ObservableCollections/RingBuffer.cs b/src/ObservableCollections/RingBuffer.cs
index 5ba6d0d..a4d24dd 100644
--- a/src/ObservableCollections/RingBuffer.cs
+++ b/src/ObservableCollections/RingBuffer.cs
@@ -1,4 +1,6 @@
-using System.Collections;
+using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace ObservableCollections
@@ -147,7 +149,7 @@ namespace ObservableCollections
public void Clear()
{
- Array.Clear(buffer);
+ Array.Clear(buffer, 0, buffer.Length);
head = 0;
count = 0;
}
diff --git a/src/ObservableCollections/Shims/Collections.cs b/src/ObservableCollections/Shims/Collections.cs
new file mode 100644
index 0000000..d20c328
--- /dev/null
+++ b/src/ObservableCollections/Shims/Collections.cs
@@ -0,0 +1,64 @@
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Collections.Generic
+{
+ internal static class CollectionExtensions
+ {
+ public static void Deconstruct(this KeyValuePair kvp, out TKey key, out TValue value)
+ {
+ key = kvp.Key;
+ value = kvp.Value;
+ }
+
+ public static bool Remove(this SortedDictionary dict, TKey key, out TValue value)
+ {
+ if (dict.TryGetValue(key, out value))
+ {
+ return dict.Remove(key);
+ }
+ return false;
+ }
+
+ public static bool Remove(this Dictionary dict, TKey key, out TValue value)
+ {
+ if (dict.TryGetValue(key, out value))
+ {
+ return dict.Remove(key);
+ }
+ return false;
+ }
+
+#if !NET6_0_OR_GREATER
+
+ public static bool TryGetNonEnumeratedCount(this IEnumerable source, out int count)
+ {
+ if (source is ICollection collection)
+ {
+ count = collection.Count;
+ return true;
+ }
+ if (source is IReadOnlyCollection rCollection)
+ {
+ count = rCollection.Count;
+ return true;
+ }
+ count = 0;
+ return false;
+ }
+
+#endif
+ }
+
+#if !NET5_0_OR_GREATER
+
+ internal interface IReadOnlySet : System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection
+ {
+ }
+
+#endif
+}
+
diff --git a/src/ObservableCollections/Shims/CompilerServices.cs b/src/ObservableCollections/Shims/CompilerServices.cs
new file mode 100644
index 0000000..07826dc
--- /dev/null
+++ b/src/ObservableCollections/Shims/CompilerServices.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Runtime.CompilerServices
+{
+ internal static class RuntimeHelpersEx
+ {
+ internal static bool IsReferenceOrContainsReferences()
+ {
+#if NETSTANDARD2_0
+ return true;
+#else
+ return RuntimeHelpers.IsReferenceOrContainsReferences();
+#endif
+ }
+ }
+}
diff --git a/src/ObservableCollections/Shims/Nullables.cs b/src/ObservableCollections/Shims/Nullables.cs
new file mode 100644
index 0000000..3e96443
--- /dev/null
+++ b/src/ObservableCollections/Shims/Nullables.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+#if NETSTANDARD2_0
+
+namespace System.Diagnostics.CodeAnalysis
+{
+ internal sealed class MaybeNullWhenAttribute : Attribute
+ {
+ public MaybeNullWhenAttribute(bool returnValue)
+ {
+ }
+ }
+
+ internal sealed class DoesNotReturnAttribute : Attribute
+ {
+ public DoesNotReturnAttribute()
+ {
+ }
+ }
+}
+
+#endif
\ No newline at end of file