ZeroAlloc.Notify is a source-generated notification library for .NET 8 and .NET 10. It provides async-first property and collection change notifications without reflection or dynamic dispatch. The Roslyn source generator eliminates runtime overhead by wiring all dispatch at compile time — no virtual dispatch, fully awaitable handlers.
The source generator is bundled into the main package — a single PackageReference is all you need:
dotnet add package ZeroAlloc.NotifyThe standalone
ZeroAlloc.Notify.Generatorpackage is still published for backwards compatibility with existing direct PackageReferences, but new consumers should reference onlyZeroAlloc.Notify.
// 1. Define a ViewModel with observable properties
[NotifyPropertyChangedAsync]
public partial class UserViewModel
{
[ObservableProperty]
private string _name = "";
[ObservableProperty]
private int _age;
}
// 2. Subscribe to async notifications
var vm = new UserViewModel();
vm.PropertyChangedAsync += async (args, ct) =>
{
Console.WriteLine($"Property '{args.PropertyName}' changed from {args.OldValue} to {args.NewValue}");
await Task.Delay(100, ct); // Non-blocking handler execution
};
// 3. Set properties — fully awaitable
await vm.SetNameAsync("Alice");
await vm.SetAgeAsync(30);ZeroAlloc.Notify provides async-first, fully awaitable handler dispatch — the only framework in this comparison where await vm.SetNameAsync(...) truly awaits all handlers. Refreshed benchmarks (.NET 10.0.7, i9-12900HK, BenchmarkDotNet v0.15.8, 5 attached handlers):
| Library | Time | Allocated | Async support |
|---|---|---|---|
Manual INotifyPropertyChanged (baseline) |
33.6 ns | 24 B | ❌ |
| PropertyChanged.Fody | 30.2 ns | 0 B | ❌ |
| CommunityToolkit.Mvvm | 55.2 ns | 0 B | ❌ |
| ZeroAlloc.Notify | 124.7 ns | 80 B | ✅ |
Honest framing: ZA.Notify is the slowest of the four and the only one that allocates — the 80 B is the ValueTask state machine for fan-out to async handlers. For pure-sync view models, Fody is the right choice (fastest, 0 B). ZA.Notify is the only library here that supports async handlers; the trade-off is the cost of that capability. At 124.7 ns / 80 B per setter, it still scales to ~8M property changes per second per thread.
See docs/performance.md for detailed benchmark results and zero-allocation design explanation.
- Property Notifications — Strongly-typed, fully async
PropertyChangedAsyncevents - Collection Changes —
CollectionChangedAsyncwith observable property support - Data Validation —
INotifyDataErrorInfoAsyncfor async error collection - Sequential & Parallel —
[InvokeSequentially]attribute for handler ordering - Compiler Diagnostics — Missing handlers and misconfigurations caught at build time
- Async-First — Fully awaitable
ValueTaskhandlers; no fire-and-forget, no callbacks - Native AOT Compatible — No reflection at runtime; all dispatch resolved at compile time
- Source Generated — Full type safety with compile-time verification
| Topic | Description |
|---|---|
| Getting Started | Install and send your first notification in five minutes |
| Observable Properties | Defining and using observable properties |
| Async Notifications | Property and collection changed notifications with await support |
| Collection Changes | Observable collections with async event dispatch |
| Validation | INotifyDataErrorInfoAsync with async error handling |
| Performance | Zero-alloc internals, detailed benchmarks, Native AOT |
| Diagnostics | ZAN001–ZAN010 source generator warnings and errors |
| Advanced Patterns | Cancellation, scoped bindings, parallel handlers |
| Testing | Unit-testing observable models and notification flows |
See the samples directory for complete working examples:
- WPF MVVM application
- ASP.NET Core data binding
- Console property notifications
- Collection change handling
MIT