Skip to content

fix: resolve builder StackOverflow, activator negative refCount, binding regression, and testing extensions#4301

Merged
glennawatson merged 6 commits intomainfrom
fix/github-issues
Feb 28, 2026
Merged

fix: resolve builder StackOverflow, activator negative refCount, binding regression, and testing extensions#4301
glennawatson merged 6 commits intomainfrom
fix/github-issues

Conversation

@glennawatson
Copy link
Contributor

@glennawatson glennawatson commented Feb 28, 2026

What's Changed

Builder converter registration no longer causes StackOverflow

Calling WithFallbackConverter, WithConverter, WithSetMethodConverter, or WithConvertersFrom on IReactiveUIBuilder previously caused a StackOverflowException due to infinite recursion. These methods now work correctly.

ViewModelActivator no longer goes into a broken state on extra Deactivate calls

If Deactivate() was called more times than Activate(), the internal reference count would go negative, preventing future activations from working. The activator now safely ignores extra deactivation calls.

Two-way bindings work again with base types like System.Object

Two-way bindings between a view model property of a derived type (e.g. string) and a view property of a base type (e.g. object) were throwing ArgumentException. This is now permitted as expected.

TestScheduler extensions (AdvanceByMs, AdvanceToMs, etc.) are discoverable again

After adding the ReactiveUI.Testing.Reactive package, AdvanceByMs, AdvanceToMs, OnNextAt, and related extensions are now available with just using ReactiveUI.Testing; -- no additional namespace import needed.

Fixes #4293
Fixes #4283
Fixes #4298
Fixes #4297


Maintainer Notes

  • IReactiveUIBuilder.cs: Added 9 converter method signatures (WithConverter x4, WithFallbackConverter x2, WithSetMethodConverter x2, WithConvertersFrom x1) to the interface. These were previously only on the concrete ReactiveUIBuilder class, causing the extension methods in BuilderMixins.cs to resolve back to themselves instead of dispatching to the implementation.
  • ViewModelActivator.cs: Replaced Interlocked.Decrement in Deactivate() with a CAS (CompareExchange) loop that refuses to decrement below zero. The ignoreRefCount path now explicitly resets to 0.
  • PropertyBinderImplementation.cs: Changed the type assignability check from && (mutual) to || (one-directional). The existing fallback conversion logic at lines 180-184 already handles one-directional assignment.
  • TestSchedulerExtensions.cs: Changed namespace from ReactiveUI.Testing.Reactive to ReactiveUI.Testing. The assembly/package name remains ReactiveUI.Testing.Reactive -- the move to a separate package is intentional to keep ReactiveUI.Testing free of the Microsoft.Reactive.Testing dependency.
  • Test updates: Added new interface members to TestReactiveUIBuilder mock in Blazor tests, removed now-unnecessary using ReactiveUI.Testing.Reactive from scheduler tests.

…ing regression, and testing extensions

- Add WithConverter, WithFallbackConverter, WithSetMethodConverter, and WithConvertersFrom to IReactiveUIBuilder interface to prevent infinite recursion in BuilderMixins extension methods (#4293)
- Guard ViewModelActivator.Deactivate() against decrementing refCount below zero using CAS loop (#4283)
- Relax two-way binding type validation from mutual assignability to one-directional assignability, fixing System.Object bindings (#4298)
- Move TestSchedulerExtensions back to ReactiveUI.Testing namespace so AdvanceByMs/AdvanceToMs are discoverable without extra using (#4297)
@glennawatson glennawatson enabled auto-merge (squash) February 28, 2026 17:46
glennawatson and others added 3 commits March 1, 2026 04:48
- Replace async void lambdas with synchronous state capture to fix TUnit0031 on Windows CI where WPF TFMs are built
… snapshots

- Add WithFallbackConverter instance/factory/null tests and IReactiveUIBuilder regression test for #4293
- Update DotNet8_0, DotNet9_0, DotNet10_0 API approval snapshots with new interface methods
- Fix IsPackable closing tag typo in ReactiveUI.Testing.Reactive.csproj
@glennawatson glennawatson merged commit 61d2b5b into main Feb 28, 2026
4 checks passed
@glennawatson glennawatson deleted the fix/github-issues branch February 28, 2026 18:19
@codecov
Copy link

codecov bot commented Feb 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.75%. Comparing base (7686990) to head (ef4e401).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4301      +/-   ##
==========================================
+ Coverage   89.68%   89.75%   +0.07%     
==========================================
  Files         251      251              
  Lines        9589     9599      +10     
  Branches     1457     1460       +3     
==========================================
+ Hits         8600     8616      +16     
+ Misses        756      749       -7     
- Partials      233      234       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

database64128 added a commit to database64128/youtube-dl-wpf that referenced this pull request Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment