DionTools.EventAsR3ObservableSourceGenerator
0.0.3-alpha.3
dotnet add package DionTools.EventAsR3ObservableSourceGenerator --version 0.0.3-alpha.3
NuGet\Install-Package DionTools.EventAsR3ObservableSourceGenerator -Version 0.0.3-alpha.3
<PackageReference Include="DionTools.EventAsR3ObservableSourceGenerator" Version="0.0.3-alpha.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="DionTools.EventAsR3ObservableSourceGenerator" Version="0.0.3-alpha.3" />
<PackageReference Include="DionTools.EventAsR3ObservableSourceGenerator"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add DionTools.EventAsR3ObservableSourceGenerator --version 0.0.3-alpha.3
#r "nuget: DionTools.EventAsR3ObservableSourceGenerator, 0.0.3-alpha.3"
#:package DionTools.EventAsR3ObservableSourceGenerator@0.0.3-alpha.3
#addin nuget:?package=DionTools.EventAsR3ObservableSourceGenerator&version=0.0.3-alpha.3&prerelease
#tool nuget:?package=DionTools.EventAsR3ObservableSourceGenerator&version=0.0.3-alpha.3&prerelease
EventAsR3ObservableSourceGenerator
A C# source generator that automatically creates extension methods to convert .NET events into R3.Observable.
Overview
Working with .NET events in a reactive programming style typically requires manual boilerplate code to convert events to observables. This source generator automates that process by analyzing your classes at compile time and generating the necessary extension methods.
Benefits:
- ✅ Type-safe observable for your events
- ✅ Supports instance events, static events, and generic types
- ✅ Configurable method naming
Features
- Instance Events: Generate observable extensions for instance-level events
- Static Events: Generate observable extensions for static events
- Generic Type Support: Full support for generic classes with type constraints
- Inherited Events: Handle events in derived classes
- Customizable Naming: Configure method name prefixes and suffixes
- Event Handler Modes: Choose between EventArgs-only or (sender, EventArgs) tuple emissions
Prerequisites
- Visual Studio 2022 Version 17.3 (Incremental Source Generator, Roslyn 4.3.0) or later
- C# 9 or later
- R3
Installation
Install via NuGet Package Manager:
dotnet add package DionTools.EventAsR3ObservableSourceGenerator
Quick Start
// 1. Define a class with events
class MyButton
{
public event EventHandler? Clicked;
}
// 2. Mark a partial class with the generation attribute
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(MyButton))]
static partial class Extensions;
// 3. Use the generated extension method
var button = new MyButton();
R3.Observable<EventArgs> clicks = button.ClickedAsObservable();
Usage
Basic Instance Events
class NormalClass
{
public event EventHandler? NormalEvent;
}
// Generate extension methods for NormalClass
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(NormalClass))]
static partial class Extensions;
// Usage
R3.Observable<EventArgs> obs = new NormalClass().NormalEventAsObservable();
Static Events
static class StaticEvents
{
public static event EventHandler? StaticEvent;
public static event ConsoleCancelEventHandler? CancelKeyPress;
}
// Generate extension methods for static events
[EventAsR3ObservableSourceGenerator.StaticEventAsObservablesGeneration(typeof(StaticEvents))]
static partial class StaticEventsExtensions;
// Usage
R3.Observable<EventArgs> obs1 = StaticEventsExtensions.StaticEventAsObservable();
R3.Observable<ConsoleCancelEventArgs> obs2 = StaticEventsExtensions.CancelKeyPressAsObservable();
Generic Classes
class GenericClass<T>
{
public event EventHandler<T>? GenericEvent;
}
class GenericClassWithConstraints<T> where T : NormalClass
{
public event EventHandler<T>? GenericEvent;
}
// Generate extension methods for generic types
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(GenericClass<>))]
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(GenericClassWithConstraints<>))]
static partial class GenericExtensions;
// Usage
R3.Observable<int> obs1 = new GenericClass<int>().GenericEventAsObservable();
R3.Observable<MyClass> obs2 = new GenericClassWithConstraints<MyClass>().GenericEventAsObservable();
Inherited Classes
class BaseClass
{
public event EventHandler? BaseEvent;
}
class DerivedClass : BaseClass
{
public new event EventHandler<string>? BaseEvent;
}
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(BaseClass))]
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(DerivedClass))]
static partial class InheritanceExtensions;
// Each class gets its own observable with the correct type
R3.Observable<EventArgs> baseObs = new BaseClass().BaseEventAsObservable();
R3.Observable<string> derivedObs = new DerivedClass().BaseEventAsObservable();
Generated Code
For a class with an event:
// Your code
class MyClass
{
public event EventHandler<int>? ValueChanged;
}
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(MyClass))]
static partial class Extensions;
The generator creates an extension method like this:
// Generated code (simplified)
static partial class Extensions
{
public static R3.Observable<int> ValueChangedAsObservable(this MyClass self, CancellationToken cancellationToken = default)
{
return EventAsR3ObservableSourceGenerator.Internals.EventObservable<MyClass, EventHandler<int>, int>(
self,
static h => (s, e) => h(e),
static (self, h) => self.ValueChanged += h,
static (self, h) => self.ValueChanged -= h,
cancellationToken
);
}
}
Configuration
EventAsObservablesGenerationOptions
You can customize the generated methods using the EventAsObservablesGenerationOptions attribute:
[EventAsR3ObservableSourceGenerator.EventAsObservablesGenerationOptions(
UseEventHandler = true,
MethodNamePrefix = "Observe",
MethodNameSuffix = ""
)]
[EventAsR3ObservableSourceGenerator.EventAsObservablesGeneration(typeof(MyClass))]
static partial class Extensions;
| Property | Description | Default |
|---|---|---|
UseEventHandler |
When true, emits (object? sender, TEventArgs args) tuples. When false, emits only TEventArgs. |
false |
MethodNamePrefix |
Prefix for generated method names | "" (empty) |
MethodNameSuffix |
Suffix for generated method names | "AsObservable" |
Example with options:
// With UseEventHandler = true
Observable<(object? sender, int args)> obs = myObject.ObserveClick();
// With UseEventHandler = false (default)
Observable<int> obs = myObject.ObserveClick();
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.3-alpha.3 | 202 | 11/2/2025 |
| 0.0.3-alpha.2 | 189 | 11/2/2025 |
| 0.0.3-alpha.1 | 190 | 11/2/2025 |
| 0.0.2-alpha.3 | 188 | 11/2/2025 |
| 0.0.2-alpha.2 | 205 | 11/2/2025 |
| 0.0.2-alpha.1 | 198 | 11/2/2025 |