$npx -y skills add Aaronontheweb/dotnet-skills --skill r3-reactive-extensionsBuild reactive/event-driven C# with R3 (Cysharp's modern reimplementation of Reactive Extensions). Covers the Observable<T>/Observer<T> model, the OnErrorResume error contract, async dispatch with AwaitOperation, Task/IAsyncEnumerable integration, TimeProvider/FrameProvider sched
| 1 | # R3: Modern Reactive Extensions for .NET |
| 2 | |
| 3 | R3 is [Cysharp's](https://github.com/Cysharp/R3) ground-up reimplementation of Reactive |
| 4 | Extensions — "the new future of dotnet/reactive and UniRx." It keeps the LINQ-over-events |
| 5 | programming model but rebuilds the core types, error contract, and scheduler to fix |
| 6 | long-standing problems in `System.Reactive` (Rx.NET). Use this skill when composing event |
| 7 | streams, UI input, timers, or push-based pipelines in C#. |
| 8 | |
| 9 | **Canonical sources** (link to these from code and docs): |
| 10 | - Repository: https://github.com/Cysharp/R3 |
| 11 | - README (full operator reference): https://github.com/Cysharp/R3/blob/main/README.md |
| 12 | - Author's design rationale: https://neuecc.medium.com/r3-a-new-modern-reimplementation-of-reactive-extensions-for-c-cf29abcc5826 |
| 13 | |
| 14 | ## When to Use This Skill |
| 15 | |
| 16 | Use this skill when: |
| 17 | - Composing **events** over time — UI input, sensor/feed updates, websocket messages, domain events |
| 18 | - You need operators like debounce, throttle, merge, combine-latest, distinct-until-changed |
| 19 | - Building **MVVM** state with `ReactiveProperty` / `BindableReactiveProperty` |
| 20 | - Bridging push-based streams with `Task` / `async` and `IAsyncEnumerable` |
| 21 | - Migrating from `System.Reactive`, UniRx, or `IObservable<T>` code |
| 22 | - You hit Rx pain points: subscriptions dying on exceptions, scheduler overhead, or leak hunting |
| 23 | |
| 24 | **Not the right tool for:** request/response I/O (use `async/await`), bounded producer/consumer |
| 25 | with **backpressure** (use `System.Threading.Channels`), or server-side stream processing with |
| 26 | batching/backpressure (use Akka.NET Streams). R3, like all Rx, is **push-based with no |
| 27 | backpressure**. See the `csharp-concurrency-patterns` skill for choosing between these. |
| 28 | |
| 29 | ## Reference Files |
| 30 | |
| 31 | - [rx-net-differences.md](rx-net-differences.md): Every meaningful difference vs System.Reactive (Rx.NET) — the new core types, the error model, operator renames, dropped APIs, the scheduler swap, and a migration checklist. |
| 32 | - [async-and-integration-patterns.md](async-and-integration-patterns.md): Common patterns — async dispatch with `AwaitOperation`, `Task` integration, `IAsyncEnumerable` round-tripping, `ReactiveProperty`/MVVM, subjects, and subscription lifecycle. |
| 33 | - [scheduling-and-concurrency.md](scheduling-and-concurrency.md): How R3 handles **concurrent updates** (the threading contract, `Synchronize`, `ObserveOn`), `TimeProvider` vs `FrameProvider`, when each is necessary, and deterministic testing with fake providers. |
| 34 | |
| 35 | > Everything in this skill was validated empirically against **R3 1.3.1**. Captured output |
| 36 | > appears in the reference files as evidence. |
| 37 | |
| 38 | --- |
| 39 | |
| 40 | ## Why R3 Exists (the "why use it") |
| 41 | |
| 42 | The author ([neuecc](https://neuecc.medium.com/r3-a-new-modern-reimplementation-of-reactive-extensions-for-c-cf29abcc5826)) |
| 43 | built R3 to fix concrete defects in `System.Reactive`: |
| 44 | |
| 45 | 1. **Exceptions silently kill subscriptions.** In Rx, one exception in the pipeline calls |
| 46 | `OnError` and *unsubscribes forever* — "a billion-dollar mistake" for long-lived event |
| 47 | streams (a single bad UI event tears down the whole subscription). R3 routes errors to |
| 48 | `OnErrorResume` and **keeps the subscription alive by default**. |
| 49 | 2. **`IScheduler` is heavy and confusing.** `ImmediateScheduler`/`Merge` were measured causing |
| 50 | real server memory/CPU bloat. R3 deletes `IScheduler` and uses .NET 8's `TimeProvider` |
| 51 | (wall-clock) plus a new `FrameProvider` (frame-clock). |
| 52 | 3. **Subscription leaks are hard to find.** R3 makes every `Observable<T>` an abstract class so |
| 53 | all subscriptions funnel through one place, enabling `ObservableTracker` to list every live |
| 54 | subscription with stack traces. |
| 55 | 4. **Rx and async were awkwardly fused.** R3 treats Rx as **event-first** and adds explicit |
| 56 | bridges (`AwaitOperation`, `FromAsync`, `ToAsyncEnumerable`) instead of pretending events |
| 57 | are pull-based sequences. |
| 58 | 5. **One library, every UI.** A platform-neutral core plus thin provider packages for Unity, |
| 59 | Godot, WPF, WinForms, Avalonia, WinUI3, MAUI, Stride, MonoGame, and Blazor. |
| 60 | |
| 61 | --- |
| 62 | |
| 63 | ## Install |
| 64 | |
| 65 | ```bash |
| 66 | dotnet add package R3 |
| 67 | # Platform glue (pick what applies): R3.WPF, R3.Avalonia, R3.WinForms, R3.Unity (UPM), |
| 68 | # R3.Godot, ObservableCollections.R3, etc. See the repo README for the full list. |
| 69 | ``` |
| 70 | |
| 71 | ```csharp |
| 72 | using R3; |
| 73 | ``` |
| 74 | |
| 75 | --- |
| 76 | |
| 77 | ## The Mental Model |
| 78 | |
| 79 | R3 replaces Rx's **interfaces** with **abstract classes**, and replaces Rx's two-method error |
| 80 | contract with a single completion that carries a result. |
| 81 | |
| 82 | ```csharp |
| 83 | public abstract class Observable<T> |
| 84 | { |
| 85 | public IDisposable Subscribe(Observer<T> observer); // tracked centrally |
| 86 | p |