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>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ObservableCollections\ObservableCollections.csproj" />
</ItemGroup>
</Project>

View File

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

View File

@ -1,9 +1,40 @@
using Microsoft.AspNetCore.Components;
using ObservableCollections;
namespace BlazorApp.Pages;
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

@ -30,7 +30,7 @@ namespace WpfApp
InitializeComponent();
this.DataContext = this;
list = new ObservableList<int>();

View File

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

View File

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

View File

@ -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<T> source)
{
if (Enumerable.TryGetNonEnumeratedCount(source, out var count))
if (source.TryGetNonEnumeratedCount(out var count))
{
var array = ArrayPool<T>.Shared.Rent(count);
@ -70,7 +72,7 @@ namespace ObservableCollections.Internal
{
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);
}
@ -79,7 +81,7 @@ namespace ObservableCollections.Internal
{
if (array != null)
{
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
array = null;
}
}

View File

@ -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<T>.Shared.Return(array!, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
ArrayPool<T>.Shared.Return(array!, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
array = newArray;
}
@ -40,7 +41,7 @@ namespace ObservableCollections.Internal
{
if (array != null)
{
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
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.Linq;
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.Linq;
namespace ObservableCollections.Internal
{

View File

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

View File

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

View File

@ -20,7 +20,15 @@ namespace ObservableCollections
public ObservableDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection)
{
#if NET6_0_OR_GREATER
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;
@ -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)
{

View File

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

View File

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

View File

@ -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<T>();
}
#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
public ObservableHashSet(int capacity)
{
this.set = new HashSet<T>(capacity);
}
#endif
public ObservableHashSet(IEnumerable<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)
{
return set.TryGetValue(equalValue, out actualValue);
}
#endif
public bool Contains(T item)
{
lock (SyncRoot)

View File

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

View File

@ -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<T>(range))

View File

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

View File

@ -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<T>.Remove(result, 0));
return true;
}
result = default;
return false;
}
}
@ -130,7 +136,7 @@ namespace ObservableCollections
}
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)
{
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()
{
return new SynchronizedEnumerator<T>(SyncRoot, queue.GetEnumerator());

View File

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

View File

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

View File

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

View File

@ -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<T>.Remove(result, 0));
return true;
}
result = default;
return false;
}
}
@ -127,7 +132,7 @@ namespace ObservableCollections
}
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)
{
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()
{
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;
namespace ObservableCollections
@ -147,7 +149,7 @@ namespace ObservableCollections
public void Clear()
{
Array.Clear(buffer);
Array.Clear(buffer, 0, buffer.Length);
head = 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