Skip to content

[Perf] Simplify internal logging with MauiLog helper and InterpolatedStringHandler #34096

@simonrozsival

Description

@simonrozsival

Description

The internal logging pattern used throughout Controls.Core is verbose and wasteful:

Application.Current?.FindMauiContext()?.CreateLogger<T>()?.LogWarning($"Cannot set {property.PropertyName} because it is readonly.");

Problems:

  1. Verbose — every call site repeats the 4-method chain
  2. Wasteful — the $"..." interpolated string is always allocated, even when Application.Current is null and the entire ?. chain short-circuits. The compiler formats the string before passing it to the method.
  3. DI overheadFindMauiContext() walks the parent chain and CreateLogger<T>() resolves from DI on every call, even though these are all cold error paths.

Proposed Fix

Introduce an internal MauiLog helper with an [InterpolatedStringHandler] that skips string formatting when logging is disabled:

// Before (4-method chain, always allocates the string)
Application.Current?.FindMauiContext()?.CreateLogger<BindableObject>()?.LogWarning($"Cannot set {property.PropertyName} because it is readonly.");

// After (1 call, zero allocation when logging is disabled)
MauiLog.Warning<BindableObject>($"Cannot set {property.PropertyName} because it is readonly.");

The WarningInterpolatedStringHandler ref struct checks Application.Current?.FindMauiContext() in its constructor. If null, it sets shouldAppend = false and the compiler skips all AppendLiteral/AppendFormatted calls — zero heap allocation.

For structured logging sites ("text {placeholder}", arg), MauiLog provides pass-through overloads that still eliminate the verbose chain.

Benchmark Results

Scenario Before After Speedup
Logging disabled (no Application.Current) ~34ns + string alloc ~1ns, 0 alloc 34x
Logging enabled Same perf Same perf 1x

Scope

~30 call sites across 24 files in Controls.Core. All are cold error paths (readonly property, invalid value, GC'd parent, etc.).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions