H073.SurfaceKit.Generators 2.0.0

Prefix Reserved
dotnet add package H073.SurfaceKit.Generators --version 2.0.0
                    
NuGet\Install-Package H073.SurfaceKit.Generators -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="H073.SurfaceKit.Generators" Version="2.0.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="H073.SurfaceKit.Generators" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="H073.SurfaceKit.Generators">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add H073.SurfaceKit.Generators --version 2.0.0
                    
#r "nuget: H073.SurfaceKit.Generators, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package H073.SurfaceKit.Generators@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=H073.SurfaceKit.Generators&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=H073.SurfaceKit.Generators&version=2.0.0
                    
Install as a Cake Tool

H073.SurfaceKit.Generators

This README was generated by a locally running AI model from a direct reading of the source.

An optional Roslyn source generator for SurfaceKit. It removes the boilerplate around component state by turning [State]/[Prop] fields into the wiring you would otherwise write by hand.

You do not need this package to use SurfaceKit — state works with State<T> on its own. Add this package when you want the [State] sugar.

Install

dotnet add package H073.SurfaceKit.Generators

It installs as a build-time analyzer: no runtime dependency, no DLL in your output. It targets netstandard2.0 (Roslyn's requirement); your own project can target anything.

What you write vs. what SurfaceKit does without it

Without this package — plain State<T>:

public class CounterView : View
{
    private readonly State<int> _count = new(0);

    public override IView Body => new Button(
        new Text($"Count: {_count.Value}"),
        () => _count.Value++);
}

With this package[State] on a partial class:

public partial class CounterView : View
{
    [State] private int _count = 0;

    public override IView Body => new Button(
        new Text($"Count: {Count}"),   // use the generated property
        () => Count++);
}

Both behave identically at runtime. The generator just writes the State<T> plumbing for you.

What [State] does (and what gets generated)

For a [State] int _count = 0; field on a partial class : View, the generator emits a partial containing:

private State<int>? __sk_state_count;
public int Count
{
    get => (__sk_state_count ??= new State<int>(_count)).Value;   // lazy-seeded from the field initializer
    set => (__sk_state_count ??= new State<int>(_count)).Value = value;
}
  • Lazy seeding — the backing State<int> is created on first access, seeded from your field's initializer (_count = 0).
  • Auto-subscribe — reading Count inside Body registers this component as a dependent of the state.
  • Invalidate on change — writing Count only invalidates (and re-evaluates) the component when the value actually changes, compared with EqualityComparer<T>.Default.

The generator also emits __TransferProps for every partial class : View. This lets the reconciler reuse a component instance across frames and copy the non-state ([Prop]) fields from the new description onto the retained instance without allocating a new object. [State]/[Binding]/readonly/const fields are excluded from the transfer.

All of this uses only generics and EqualityComparer<T>.Default — no reflection — so it stays Native-AOT compatible.

Property naming

The generated property name is the field name with a leading _ or m_ stripped and the first letter upper-cased:

Field Generated property
_count Count
m_isOpen IsOpen
value Value

If stripping the prefix would collide with the original field name, no property is emitted for that field.

What to watch out for

  • The class must be partial. [State]/[Prop] live on a partial class : View; without partial, the generator can't add the other half.
  • Use the generated property, not the field. Read/write Count, not _count, inside Body and handlers — only the property path subscribes and invalidates. The raw field is just the initial seed.
  • The field initializer is the initial value only. After first access the value lives in the backing State<T>; later assignments to the field don't move the state.
  • Don't also declare the generated name. Declaring your own Count alongside _count collides — rename one.
  • Reference types compare by reference. Invalidation uses EqualityComparer<T>.Default; mutating a List<T> in place won't be detected. Reassign (Items = newList) or use an immutable/value type to trigger a refresh.
  • Match versions. Keep this package's version aligned with your H073.SurfaceKit version.

License

MIT

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has 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
2.0.0 93 7/1/2026