Repository navigation
feat(reactive): add ContainerDisposable for CompositeDisposable interop - #169
Conversation
- Add ContainerDisposable, a MultipleDisposable that converts implicitly to a CompositeDisposable it owns and disposes, so a disposal group flows into APIs written against System.Reactive without a hand conversion. - MultipleDisposable ships in the dependency-free ReactiveUI.Disposables package and cannot name CompositeDisposable, so the seam has to live here. - Add a DisposeWith overload taking the container. Without it a call site that imports this namespace and System.Reactive's fluent disposal helpers has two equally-good candidates and is ambiguous.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #169 +/- ##
==========================================
+ Coverage 98.14% 98.15% +0.01%
==========================================
Files 703 705 +2
Lines 21733 21761 +28
Branches 2679 2680 +1
==========================================
+ Hits 21330 21360 +30
+ Misses 199 197 -2
Partials 204 204 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
The lifetimes are only tied in one direction. If the user loses the |
|
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |



What kind of change does this PR introduce?
Feature - new public API on
ReactiveUI.Primitives.Reactive.What is the new behavior?
ReactiveUI.Primitives.ReactiveshipsContainerDisposable, a disposal group a System.Reactive consumer can use as aCompositeDisposable.ContainerDisposableis aMultipleDisposablethat converts implicitly to aCompositeDisposableit owns.DisposeWith, to a library that takes aCompositeDisposable, or to your own helper - no conversion at the call site.MultipleDisposable.Add.Clear()andRemove()dispose the composite along with everything else; the next conversion hands back a fresh one, so the container stays usable.DisposeWithgains an overload that takes the container. A container is convertible toCompositeDisposable, so without this overload a call site importing bothReactiveUI.Primitives.Reactiveand System.Reactive's fluent disposal helpers has two equally-good candidates and does not compile. Taking the container exactly makes this an identity match, which wins outright.The intended consumer is
ReactiveUI.Reactive, whoseWhenActivated(Action<MultipleDisposable>)overloads can hand out aContainerDisposableinstead. That is a follow-up in the ReactiveUI repo and is blocked on this shipping - ReactiveUI consumes Primitives as a package reference.What is the current behavior?
MultipleDisposableships inReactiveUI.Disposables, which deliberately has no System.Reactive dependency, so it cannot nameCompositeDisposableand no conversion between them exists. Code that gets aMultipleDisposablefromWhenActivatedand calls System.Reactive'sDisposeWithon it does not compile; the workaround is to importReactiveUI.Primitives.Reactivefor the PrimitivesDisposeWithinstead.Relates to reactiveui/ReactiveUI#4434.
What might this PR break?
None. The change is additive:
ContainerDisposableis new, and the existingDisposeWith(MultipleDisposable)overload is untouched.DisposeWithbinds to the new overload by identity, so the two overloads coexist whether or not System.Reactive's fluent disposal helpers are also imported.Two things worth knowing when using it:
ICollection<IDisposable>view counts the composite as a single entry.Count,ContainsandRemovedo not see through it to registrations made on the composite..Reactiveflavour.Checklist
mainbranchAdditional information
The hand-written files are
ContainerDisposable.cs,LinqExtensions.ContainerDisposable.cs,ContainerDisposableTests.cs, the added tests inLinqExtensionsTests.cs, and a README paragraph. The rest of the diff is the same two entries repeated across the per-TFM public API baselines.LinqExtensionsTests.csnow importsSystem.Reactive.Disposables.Fluentdeliberately: that import is what makes the overload-resolution guard a compile-time test rather than a comment.