Skip to content

About

A zero-allocation async INPC library for .NET. Roslyn source generator wires PropertyChanged/PropertyChanging dispatch at compile time — no reflection, fully awaitable.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

309 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZeroAlloc.Notify

NuGet Build codecov License: MIT AOT GitHub Sponsors

Source-generated, awaitable INotifyPropertyChanged for .NET: await vm.SetNameAsync("Alice") returns only after every async handler has finished, with no reflection and NativeAOT support.

Why ZeroAlloc.Notify

  • Setters you can await. Async validation, saving or coordinated state changes complete before the setter returns. CommunityToolkit.Mvvm and PropertyChanged.Fody only offer synchronous notifications.
  • 0 B when nobody listens. The generated setter creates event args only when there are subscribers; tests assert 0 B for reference-type and value-type properties. With subscribers, a change costs its args object, 40 B, plus a box per value-type value; tests pin both figures.
  • Works under NativeAOT and trimming. All plumbing is generated at compile time; CI publishes and runs a NativeAOT sample on every build.
  • Compile-time diagnostics. A class that is not partial, a record, or a stray [ObservableProperty] is reported by the build, not discovered at runtime.

Install

dotnet add package ZeroAlloc.Notify

The source generator ships inside the package.

Quick start

using ZeroAlloc.Notify;

var user = new UserViewModel();

user.PropertyChangedAsync += async (args, ct) =>
{
    await Task.Delay(100, ct);  // e.g. save to a server
    Console.WriteLine($"{args.PropertyName}: {args.OldValue} -> {args.NewValue}, saved");
};

await user.SetNameAsync("Alice");  // returns after the handler has saved
await user.SetAgeAsync(30);

[NotifyPropertyChangedAsync]
public partial class UserViewModel
{
    [ObservableProperty] private string _name = "";
    [ObservableProperty] private int _age;
}

The generator writes the Name and Age properties, the SetNameAsync and SetAgeAsync setters and the PropertyChangedAsync event.

What you get

  • Async property notifications, before and after a change: [NotifyPropertyChangedAsync] and [NotifyPropertyChangingAsync]. Observable properties
  • Async collection notifications with [NotifyCollectionChangedAsync]. Collection changes
  • Async validation through INotifyDataErrorInfoAsync. Validation
  • Parallel handlers by default, sequential on request with [InvokeSequentially], and a CancellationToken on every setter. Async notifications
  • Build-time checks, ZAN001 to ZAN006. Diagnostics
  • Targets netstandard2.0, net8.0 and net10.0.
  • Built on ZeroAlloc.AsyncEvents, the async event primitive behind every handler.

Performance

One property change with five handlers attached. .NET 10, BenchmarkDotNet, same run; the ratio is against a hand-written INotifyPropertyChanged, computed from the published means.

Library Ratio Allocated Async handlers
Manual INotifyPropertyChanged 1.00 24 B no
PropertyChanged.Fody 0.82 0 B no
CommunityToolkit.Mvvm 1.43 0 B no
ZeroAlloc.Notify 3.20 40 B yes

Awaitable handlers have a cost: Notify is the slowest of the four and allocates its args object when someone listens. For purely synchronous view models, Fody is the faster choice. Allocation breakdown, design notes and full numbers: docs/performance.md.

Learn more

About

A zero-allocation async INPC library for .NET. Roslyn source generator wires PropertyChanged/PropertyChanging dispatch at compile time — no reflection, fully awaitable.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages