netstandard2.0;2.1;net5.0

This commit is contained in:
neuecc 2021-09-02 16:37:20 +09:00
parent 81be2a3e18
commit cfaefc4454
28 changed files with 260 additions and 43 deletions

View File

@ -4,4 +4,8 @@
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ObservableCollections\ObservableCollections.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -1,7 +1,12 @@
@page "/" @page "/"
<h1>Hello, world!</h1> <button @onclick=OnClick>button</button>
Welcome to your new app. <table>
@foreach (var item in ItemsView)
<SurveyPrompt Title="How is Blazor working for you?" /> {
<tr>
<td>@item</td>
</tr>
}
</table>

View File

@ -1,9 +1,40 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using ObservableCollections;
namespace BlazorApp.Pages; namespace BlazorApp.Pages;
public partial class Index public partial class Index
{ {
ObservableList<int> list;
public ISynchronizedView<int, int> ItemsView { get; set; }
int adder = 99;
RenderFragment fragment;
protected override void OnInitialized()
{
list = new ObservableList<int>();
list.AddRange(new[] { 1, 10, 188 });
ItemsView = list.CreateSortedView(x => x, x => x, comparer: Comparer<int>.Default).WithINotifyCollectionChanged();
fragment = builder =>
{
builder.GetFrames();
};
}
void OnClick()
{
ThreadPool.QueueUserWorkItem(_ =>
{
list.Add(adder++);
_ = InvokeAsync(StateHasChanged);
});
}
} }

View File

@ -1,4 +1,6 @@
using ObservableCollections.Internal; #nullable disable
using ObservableCollections.Internal;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,4 +1,6 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;

View File

@ -1,5 +1,7 @@
using System.Buffers; using System;
using System.Buffers;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace ObservableCollections.Internal namespace ObservableCollections.Internal
@ -24,7 +26,7 @@ namespace ObservableCollections.Internal
public CloneCollection(IEnumerable<T> source) public CloneCollection(IEnumerable<T> source)
{ {
if (Enumerable.TryGetNonEnumeratedCount(source, out var count)) if (source.TryGetNonEnumeratedCount(out var count))
{ {
var array = ArrayPool<T>.Shared.Rent(count); var array = ArrayPool<T>.Shared.Rent(count);
@ -70,7 +72,7 @@ namespace ObservableCollections.Internal
{ {
if (array.Length == index) if (array.Length == index)
{ {
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>()); ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
} }
array = ArrayPool<T>.Shared.Rent(index * 2); array = ArrayPool<T>.Shared.Rent(index * 2);
} }
@ -79,7 +81,7 @@ namespace ObservableCollections.Internal
{ {
if (array != null) if (array != null)
{ {
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>()); ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
array = null; array = null;
} }
} }

View File

@ -1,4 +1,5 @@
using System.Buffers; using System;
using System.Buffers;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -32,7 +33,7 @@ namespace ObservableCollections.Internal
void EnsureCapacity() void EnsureCapacity()
{ {
var newArray = array.AsSpan().ToArray(); var newArray = array.AsSpan().ToArray();
ArrayPool<T>.Shared.Return(array!, RuntimeHelpers.IsReferenceOrContainsReferences<T>()); ArrayPool<T>.Shared.Return(array!, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
array = newArray; array = newArray;
} }
@ -40,7 +41,7 @@ namespace ObservableCollections.Internal
{ {
if (array != null) if (array != null)
{ {
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>()); ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
array = null; array = null;
} }
} }

View File

@ -1,5 +1,8 @@
using System.Collections; using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections.Internal namespace ObservableCollections.Internal
{ {

View File

@ -1,5 +1,8 @@
using System.Collections; using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections.Internal namespace ObservableCollections.Internal
{ {

View File

@ -1,8 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFrameworks>netstandard2.0;netstandard2.1;net5.0;net6.0</TargetFrameworks>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>10.0</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="$(TargetFramework) == 'netstandard2.0'">
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
</Project> </Project>

View File

@ -1,6 +1,9 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {

View File

@ -20,7 +20,15 @@ namespace ObservableCollections
public ObservableDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) public ObservableDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection)
{ {
#if NET6_0_OR_GREATER
this.dictionary = new Dictionary<TKey, TValue>(collection); this.dictionary = new Dictionary<TKey, TValue>(collection);
#else
this.dictionary = new Dictionary<TKey, TValue>();
foreach (var item in collection)
{
dictionary.Add(item.Key, item.Value);
}
#endif
} }
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? CollectionChanged; public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? CollectionChanged;
@ -191,7 +199,9 @@ namespace ObservableCollections
} }
} }
#pragma warning disable CS8767
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
#pragma warning restore CS8767
{ {
lock (SyncRoot) lock (SyncRoot)
{ {

View File

@ -1,5 +1,7 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
namespace ObservableCollections namespace ObservableCollections
{ {

View File

@ -1,6 +1,9 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System;
using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {

View File

@ -1,5 +1,7 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace ObservableCollections namespace ObservableCollections
@ -16,11 +18,15 @@ namespace ObservableCollections
this.set = new HashSet<T>(); this.set = new HashSet<T>();
} }
#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
public ObservableHashSet(int capacity) public ObservableHashSet(int capacity)
{ {
this.set = new HashSet<T>(capacity); this.set = new HashSet<T>(capacity);
} }
#endif
public ObservableHashSet(IEnumerable<T> collection) public ObservableHashSet(IEnumerable<T> collection)
{ {
this.set = new HashSet<T>(collection); this.set = new HashSet<T>(collection);
@ -174,11 +180,15 @@ namespace ObservableCollections
} }
} }
#if !NETSTANDARD2_0
public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue) public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue)
{ {
return set.TryGetValue(equalValue, out actualValue); return set.TryGetValue(equalValue, out actualValue);
} }
#endif
public bool Contains(T item) public bool Contains(T item)
{ {
lock (SyncRoot) lock (SyncRoot)

View File

@ -1,6 +1,9 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {

View File

@ -102,7 +102,6 @@ namespace ObservableCollections
lock (SyncRoot) lock (SyncRoot)
{ {
var index = list.Count; var index = list.Count;
list.EnsureCapacity(items.Length);
foreach (var item in items) foreach (var item in items)
{ {
list.Add(item); list.Add(item);
@ -242,7 +241,11 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
#if NET5_0_OR_GREATER
var range = CollectionsMarshal.AsSpan(list).Slice(index, count); var range = CollectionsMarshal.AsSpan(list).Slice(index, count);
#else
var range = list.GetRange(index, count);
#endif
// require copy before remove // require copy before remove
using (var xs = new CloneCollection<T>(range)) using (var xs = new CloneCollection<T>(range))

View File

@ -1,6 +1,9 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System.Collections; using System.Collections;
using System.Collections.Specialized; using System.Collections.Specialized;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {
@ -120,7 +123,6 @@ namespace ObservableCollections
} }
else else
{ {
queue.EnsureCapacity(e.NewItems.Length);
foreach (var item in e.NewItems) foreach (var item in e.NewItems)
{ {
var v = (item, selector(item)); var v = (item, selector(item));

View File

@ -3,6 +3,10 @@ using System.Buffers;
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {
@ -105,11 +109,13 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
if (queue.TryDequeue(out result)) if (queue.Count != 0)
{ {
result = queue.Dequeue();
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(result, 0)); CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(result, 0));
return true; return true;
} }
result = default;
return false; return false;
} }
} }
@ -130,7 +136,7 @@ namespace ObservableCollections
} }
finally finally
{ {
ArrayPool<T>.Shared.Return(dest, RuntimeHelpers.IsReferenceOrContainsReferences<T>()); ArrayPool<T>.Shared.Return(dest, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
} }
} }
} }
@ -169,7 +175,13 @@ namespace ObservableCollections
{ {
lock (SyncRoot) 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<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, queue.GetEnumerator()); return new SynchronizedEnumerator<T>(SyncRoot, queue.GetEnumerator());

View File

@ -1,6 +1,9 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {

View File

@ -1,4 +1,7 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections; using System.Collections;
namespace ObservableCollections namespace ObservableCollections

View File

@ -1,6 +1,9 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {
@ -120,7 +123,6 @@ namespace ObservableCollections
} }
else else
{ {
stack.EnsureCapacity(e.NewItems.Length);
foreach (var item in e.NewItems) foreach (var item in e.NewItems)
{ {
var v = (item, selector(item)); var v = (item, selector(item));

View File

@ -1,6 +1,8 @@
using ObservableCollections.Internal; using ObservableCollections.Internal;
using System;
using System.Buffers; using System.Buffers;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -102,11 +104,14 @@ namespace ObservableCollections
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
if (stack.TryPop(out result)) if (stack.Count != 0)
{ {
result = stack.Pop();
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(result, 0)); CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(result, 0));
return true; return true;
} }
result = default;
return false; return false;
} }
} }
@ -127,7 +132,7 @@ namespace ObservableCollections
} }
finally finally
{ {
ArrayPool<T>.Shared.Return(dest, RuntimeHelpers.IsReferenceOrContainsReferences<T>()); ArrayPool<T>.Shared.Return(dest, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
} }
} }
} }
@ -166,7 +171,13 @@ namespace ObservableCollections
{ {
lock (SyncRoot) 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<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
return new SynchronizedEnumerator<T>(SyncRoot, stack.GetEnumerator()); return new SynchronizedEnumerator<T>(SyncRoot, stack.GetEnumerator());

View File

@ -1,4 +1,6 @@
using System.Collections; using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace ObservableCollections namespace ObservableCollections
@ -147,7 +149,7 @@ namespace ObservableCollections
public void Clear() public void Clear()
{ {
Array.Clear(buffer); Array.Clear(buffer, 0, buffer.Length);
head = 0; head = 0;
count = 0; count = 0;
} }

View File

@ -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<TKey, TValue>(this KeyValuePair<TKey, TValue> kvp, out TKey key, out TValue value)
{
key = kvp.Key;
value = kvp.Value;
}
public static bool Remove<TKey, TValue>(this SortedDictionary<TKey, TValue> dict, TKey key, out TValue value)
{
if (dict.TryGetValue(key, out value))
{
return dict.Remove(key);
}
return false;
}
public static bool Remove<TKey, TValue>(this Dictionary<TKey, TValue> 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<T>(this IEnumerable<T> source, out int count)
{
if (source is ICollection<T> collection)
{
count = collection.Count;
return true;
}
if (source is IReadOnlyCollection<T> rCollection)
{
count = rCollection.Count;
return true;
}
count = 0;
return false;
}
#endif
}
#if !NET5_0_OR_GREATER
internal interface IReadOnlySet<T> : System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>
{
}
#endif
}

View File

@ -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<T>()
{
#if NETSTANDARD2_0
return true;
#else
return RuntimeHelpers.IsReferenceOrContainsReferences<T>();
#endif
}
}
}

View File

@ -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