Add IObservableCollection<>.ObserveCountChanged

This commit is contained in:
hadashiA 2024-02-02 16:55:51 +09:00
parent 320012d840
commit b912fc6324
3 changed files with 89 additions and 2 deletions

View File

@ -36,6 +36,11 @@ public static class ObservableCollectionR3Extensions
{
return new ObservableCollectionReset<T>(source, cancellationToken);
}
public static Observable<int> ObserveCountChanged<T>(this IObservableCollection<T> source, bool notifyCurrentCount = false, CancellationToken cancellationToken = default)
{
return new ObservableCollectionCountChanged<T>(source, notifyCurrentCount, cancellationToken);
}
}
sealed class ObservableCollectionAdd<T>(IObservableCollection<T> collection, CancellationToken cancellationToken)
@ -180,6 +185,49 @@ sealed class ObservableCollectionReset<T>(IObservableCollection<T> collection, C
}
}
sealed class ObservableCollectionCountChanged<T>(IObservableCollection<T> collection, bool notifyCurrentCount, CancellationToken cancellationToken)
: Observable<int>
{
protected override IDisposable SubscribeCore(Observer<int> observer)
{
return new _ObservableCollectionCountChanged(collection, notifyCurrentCount, observer, cancellationToken);
}
sealed class _ObservableCollectionCountChanged : ObservableCollectionObserverBase<T, int>
{
readonly IObservableCollection<T> collection;
int countPrev;
public _ObservableCollectionCountChanged(
IObservableCollection<T> collection,
bool notifyCurrentCount,
Observer<int> observer,
CancellationToken cancellationToken) : base(collection, observer, cancellationToken)
{
this.collection = collection;
this.countPrev = collection.Count;
if (notifyCurrentCount)
{
observer.OnNext(collection.Count);
}
}
protected override void Handler(in NotifyCollectionChangedEventArgs<T> eventArgs)
{
switch (eventArgs.Action)
{
case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Remove:
case NotifyCollectionChangedAction.Reset when countPrev != collection.Count:
observer.OnNext(collection.Count);
break;
}
countPrev = collection.Count;
}
}
}
abstract class ObservableCollectionObserverBase<T, TEvent> : IDisposable
{
protected readonly IObservableCollection<T> collection;

View File

@ -49,7 +49,7 @@ namespace ObservableCollections.Internal
}
else
{
var array = ArrayPool<T>.Shared.Rent(count);
var array = ArrayPool<T>.Shared.Rent(16);
var i = 0;
foreach (var item in source)
@ -75,9 +75,9 @@ namespace ObservableCollections.Internal
if (array.Length == index)
{
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
}
array = ArrayPool<T>.Shared.Rent(index * 2);
}
}
public void Dispose()
{

View File

@ -132,4 +132,43 @@ public class ObservableCollectionExtensionsTest
collection.Move(1, 2);
events.Count.Should().Be(1);
}
[Fact]
public void ObserveCountChanged()
{
var events = new List<int>();
var collection = new ObservableList<int>([111, 222, 333]);
using var _ = collection.ObserveCountChanged().Subscribe(count => events.Add(count));
events.Should().BeEmpty();
collection.Add(444);
events[0].Should().Be(4);
collection.Remove(111);
events[1].Should().Be(3);
collection.Move(0, 1);
events.Count.Should().Be(2);
collection[0] = 999;
events.Count.Should().Be(2);
collection.Clear();
events[2].Should().Be(0);
collection.Clear();
events.Count.Should().Be(3);
}
[Fact]
public void ObserveCountChanged_NotifyCurrent()
{
var events = new List<int>();
var collection = new ObservableList<int>([111, 222, 333]);
var subscription = collection.ObserveCountChanged(notifyCurrentCount: true).Subscribe(count => events.Add(count));
events[0].Should().Be(3);
}
}