From 64cdc622fd37d4e1c4ef5b3c9b9fc2d8f6eb2d76 Mon Sep 17 00:00:00 2001 From: Mason Date: Fri, 17 Apr 2026 14:41:22 -0400 Subject: [PATCH 1/2] fix: 120 ObserveCountChanged misses count if observer has side effect --- .../ObservableCollectionR3Extensions.cs | 2 +- .../ObservableCollectionExtensionsTest.cs | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs index 16d681b..2b4c0d3 100644 --- a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs +++ b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs @@ -438,10 +438,10 @@ protected override void Handler(in NotifyCollectionChangedEventArgs eventArgs case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Reset when countPrev != collection.Count: + countPrev = collection.Count; observer.OnNext(collection.Count); break; } - countPrev = collection.Count; } } } diff --git a/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs b/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs index 85f9355..ff26392 100644 --- a/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs +++ b/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs @@ -161,7 +161,7 @@ public void ObserveReplace() collection[1] = 444; events.Count.Should().Be(1); } - + [Fact] public void ObserveDictionaryReplace() { @@ -247,6 +247,27 @@ public void ObserveCountChanged() events.Count.Should().Be(3); } + [Fact] + public void ObserveCountChanged_WithSideEffect() + { + var events = new List(); + var collection = new ObservableList([]); + + using var _ = collection.ObserveCountChanged().Subscribe(count => + { + events.Add(count); + // Side effect - when count is 1, clear the list + if(count == 1) collection.Clear(); + }); + + events.Should().BeEmpty(); + + collection.Add(12); + + collection.Count.Should().Be(0); + events.Should().BeEquivalentTo([1, 0]); + } + [Fact] public void ObserveCountChanged_NotifyCurrent() { @@ -257,4 +278,4 @@ public void ObserveCountChanged_NotifyCurrent() .Subscribe(count => events.Add(count)); events[0].Should().Be(3); } -} \ No newline at end of file +} From e1e9ca57368b13d99a25729c4bfa7d21e5bbe474 Mon Sep 17 00:00:00 2001 From: Mason Date: Fri, 11 Sep 2026 00:21:15 -0400 Subject: [PATCH 2/2] address comments --- .../ObservableCollectionR3Extensions.View.cs | 7 +++--- .../ObservableCollectionR3Extensions.cs | 5 ++-- .../ObservableCollectionExtensionsTest.cs | 24 ++++++++++++++++++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.View.cs b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.View.cs index 3bc84d2..5c17387 100644 --- a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.View.cs +++ b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.View.cs @@ -416,10 +416,11 @@ protected override void Handler(in SynchronizedViewChangedEventArgs ev case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Reset when countPrev != source.Count: - observer.OnNext(source.Count); + var count = source.Count; + countPrev = count; + observer.OnNext(count); break; } - countPrev = source.Count; } } } @@ -506,4 +507,4 @@ public void Dispose() } protected abstract void Handler(in SynchronizedViewChangedEventArgs eventArgs); -} \ No newline at end of file +} diff --git a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs index 2b4c0d3..3af7cf6 100644 --- a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs +++ b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs @@ -438,8 +438,9 @@ protected override void Handler(in NotifyCollectionChangedEventArgs eventArgs case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Reset when countPrev != collection.Count: - countPrev = collection.Count; - observer.OnNext(collection.Count); + var count = collection.Count; + countPrev = count; + observer.OnNext(count); break; } } diff --git a/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs b/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs index ff26392..fdd1688 100644 --- a/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs +++ b/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs @@ -265,7 +265,29 @@ public void ObserveCountChanged_WithSideEffect() collection.Add(12); collection.Count.Should().Be(0); - events.Should().BeEquivalentTo([1, 0]); + events.Should().Equal([1, 0]); + } + + [Fact] + public void ObserveViewCountChanged_WithSideEffect() + { + var events = new List(); + var collection = new ObservableList([]); + using var view = collection.CreateView(x => x); + + using var _ = view.ObserveCountChanged().Subscribe(count => + { + events.Add(count); + // Side effect - when count is 1, clear the list + if (count == 1) collection.Clear(); + }); + + events.Should().BeEmpty(); + + collection.Add(12); + + view.Count.Should().Be(0); + events.Should().Equal([1, 0]); } [Fact]