Skip to content

Instantly share code, notes, and snippets.

@StephaneDelcroix
Last active January 28, 2026 12:07
Show Gist options
  • Select an option

  • Save StephaneDelcroix/36cc853aa004169609e2176b5c0ebc0a to your computer and use it in GitHub Desktop.

Select an option

Save StephaneDelcroix/36cc853aa004169609e2176b5c0ebc0a to your computer and use it in GitHub Desktop.
Lazy ResourceDictionary + x:Shared spec for .NET MAUI

Lazy ResourceDictionary Specification

Problem

  1. Slow inflation time: All resources are instantiated upfront during XAML inflation, even if never used
  2. No x:Shared support: Resources that need parenting (e.g., StrokeShape) cannot be StaticResources because the same instance is shared - causing crashes when multiple elements try to parent the same object

Proposed Solution

Store Func<object> factories instead of object instances in ResourceDictionary. Resources are created on-demand when accessed.

API Changes

public class ResourceDictionary
{
    // NEW: Add a resource factory instead of an instance
    [EditorBrowsable(EditorBrowsableState.Never)]
    public void AddFactory(string key, Func<object> factory, bool shared = true);
    
    // NEW: Add an implicit style factory (uses TargetType.FullName as key)
    [EditorBrowsable(EditorBrowsableState.Never)]
    public void AddFactory(Func<Style> factory, bool shared = true);
    
    // MODIFIED: TryGetValue now invokes factory if stored value is a factory
    // For shared=true: invoke once, cache result
    // For shared=false: invoke every time (x:Shared="false")
}

Internal Storage

// Wrapper to distinguish factories from regular values
internal readonly struct LazyResource
{
    public Func<object> Factory { get; }
    public bool Shared { get; }
}

// _innerDictionary stores either:
// - object (existing behavior)
// - LazyResource (new lazy behavior)

Behavior

Scenario shared=true (default) shared=false
First access Invoke factory, cache result, return Invoke factory, return
Subsequent Return cached Invoke factory, return

Source Generator Integration

SourceGen-only: This is a compile-time optimization. XamlC cannot emit lambdas.

// Generated code (SourceGen)
Resources.AddFactory("MyStyle", () => new Style { ... }, shared: true);  // explicit key
Resources.AddFactory(() => new Style { TargetType = typeof(Button), ... });  // implicit style
Resources.AddFactory("MyShape", () => new RoundRectangle { ... }, shared: false);

// XamlC continues to emit
Resources.Add("MyStyle", new Style { ... });

XAML Syntax

<!-- Default: x:Shared="true" (cached, current behavior) -->
<Style x:Key="MyStyle" TargetType="Button">...</Style>

<!-- New: x:Shared="false" (new instance per access) -->
<RoundRectangle x:Key="MyShape" x:Shared="false" CornerRadius="10"/>

Scope

Inflator Lazy RD x:Shared
SourceGen
Runtime ❌ (could add)
XamlC ❌ (possible but hard)

API Surface

AddFactory is [EditorBrowsable(Never)] - internal use only.

Public iteration behavior:

  • Keys → returns keys only, does NOT invoke factories
  • Values → resolves lazy values (invokes factory, caches if shared)
  • GetEnumerator() / foreach → returns KeyValuePair<string, object> with resolved values

Internal _innerDictionary stores LazyResource, but public API always resolves — no breaking change.

Benefits

  • Faster startup: Resources created only when needed
  • 🔧 x:Shared for free: StrokeShape in StaticResource finally works
  • 📦 No runtime cost for unused resources

Risks

  • ⚠️ x:Shared only works with SourceGen (acceptable trade-off)

Under Consideration

  • Default x:Shared=false via attribute: Mark types like StrokeShape, RoundRectangle, etc. with an attribute (e.g., [NotSharedByDefault]) so SourceGen automatically treats them as x:Shared="false" without explicit XAML markup. This would prevent common pitfalls where elements that need parenting are incorrectly shared.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment