Prowl.Ember 3.1.0

dotnet add package Prowl.Ember --version 3.1.0
                    
NuGet\Install-Package Prowl.Ember -Version 3.1.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="Prowl.Ember" Version="3.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Prowl.Ember" Version="3.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Prowl.Ember" />
                    
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 Prowl.Ember --version 3.1.0
                    
#r "nuget: Prowl.Ember, 3.1.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 Prowl.Ember@3.1.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=Prowl.Ember&version=3.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Prowl.Ember&version=3.1.0
                    
Install as a Cake Tool

Prowl.Ember

In-place assembly state migration for hot reload, for .NET.

When you recompile code at runtime, the new assembly is loaded alongside the previous one. Ember walks the live object graph from watched static fields and caller supplied roots, and for every object whose type was replaced it produces a replacement, carries its state across, and repoints every reference to it - preserving reference identity and cycles. Both assemblies stay loaded, correctness never depends on the previous one unloading.

This idea, and some of its implementation, is based on the work by s&box engine.

What it migrates

  • Objects and cycles - fields carried across the swap, references repointed, identity and cycles preserved. The walk is a worklist rather than a recursion, so graph depth cannot exhaust the stack.
  • Delegates - single and multicast, including compiler generated lambdas, closures, local functions, and state machines, matched across the swap by reading the replaced IL with Mono.Cecil.
  • Generic and anonymous types - reconstructed against the current assembly; anonymous types re-matched by property name.
  • Collections - lists, arrays (multidimensional and jagged), the dictionary and set families, concurrent and immutable containers, ConditionalWeakTable, WeakReference, and your own subclasses of any of them, rebuilt so comparers and hash codes stay valid and the subclass's own state survives.
  • Reflection handles - Assembly, Type, MemberInfo, ParameterInfo.
  • New fields - get their declared initializer value, replayed from the field initializer IL with no constructor side effects.
  • System.Text.Json metadata caches are cleared around the reload.

Usage

using Prowl.Ember;

// Long lived: scope, migrators, and root providers.
var engine = ReloadEngine.Create(options =>
{
    // Ember reads the replaced IL with Cecil, so hand it the bytes each assembly was loaded from.
    options.AssemblyBytes = assembly => LoadedBytesFor(assembly);
    options.Diagnostics = new DelegateDiagnosticSink(d => Console.WriteLine($"{d.Id} {d.Message}"));

    options.Scope.Include(gameAssembly);   // walk its statics to find live instances
    options.Scope.ExcludePrefix("Silk.NET"); // never descend into native or third party internals
});

// Per reload: an immutable description of what changed and where to start.
var report = engine.Apply(ReloadRequest.Create()
    .Replace(previousAssembly, currentAssembly)
    .Roots(scene.AllComponents)
    .Build());

foreach (var diagnostic in report.Errors)
    Console.Error.WriteLine(diagnostic);

scene.Rebind(report.Replaced, report.Dropped);

ReloadReport carries every diagnostic with a stable code, the old to new map for every replaced object (not just the roots), the objects whose type was removed, and per phase counts and timings.

Opting out and lifecycle hooks

Everything user code touches lives in Prowl.Ember.Contracts, which has no dependencies and is AOT safe.

  • [ReloadIgnore] on a field, auto property, or type leaves it out of the migration. On a replacement the field gets what a freshly constructed instance would have, not null.
  • [ReloadInitializer("Method")] on a newly added field runs the named method to initialize it, once every other field is populated.
  • IReloadAware gives you OnReloadDetach on the outgoing instance and OnReloadAttach on the incoming one, with a typed ReloadState carried between them, for tearing down and re-establishing registrations, native handles, or event subscriptions.
  • IReloadObserver gives you OnReloadPreserved and OnReloadDropped, the two outcomes that are not a replacement.
  • ReloadCache<TKey, TValue> is a cache that empties itself across a reload, for the type keyed maps that would otherwise pin what they were derived from.

License

MIT - part of the Prowl Anthology.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
3.1.0 83 8/10/2026
3.0.5 88 8/9/2026
3.0.4 88 8/9/2026
3.0.1 135 8/4/2026
3.0.0 114 8/2/2026
2.9.3 105 7/30/2026
2.9.2 96 7/30/2026
2.9.1 92 7/30/2026
2.8.6 102 7/30/2026