Rebuild preserves compatible local state; restart does not.
Rebuild()
Re-evaluates declarative builder boundaries and reconciles compatible widgets in place.
Restart(widget)
Mounts a fresh root, then releases the old tree. Mount-local state is reset.
If the replacement root cannot mount, Restart leaves the existing screen active. These are application lifecycle operations, not a C# compiler patcher.
Register callbacks at the bootstrap boundary.
After mounting, register callbacks that remain owned by your application. Dispose the registration before disposing the mount.
private IDisposable? _previewToolbar;
private void ConnectPreviewTools() {
_previewToolbar = PlayModePreviewToolbar.Register(
reload: () => _mount?.Rebuild(),
restart: () => _mount?.Restart(CreateApplication()));
}
private void OnDisable() {
_previewToolbar?.Dispose();
_previewToolbar = null;
_mount?.Dispose();
}Changed C# source still requires Unity to reload assemblies.
Reassemble does not compile changed scripts. A standard Unity compilation reloads managed assemblies, so continuing the same mount through that boundary is unsupported. Compile & Restart exits Play Mode, requests a refresh and compilation, then re-enters after a successful quiet period.
A method-patching solution can apply supported method-body changes without a domain reload; then Reassemble can rerun LumaFlow builders. Type-shape, field and generic-layout changes still require a restart.
Keep the handle where native and framework lifecycles meet.
The MonoBehaviour that owns the UIDocument owns the MountHandle and optional toolbar registration. Application widgets should not retain native elements or call Mount themselves.