From a530bbeb997d91f5f9f165747e7954132d69f6f2 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 3 Dec 2024 16:59:27 +0000 Subject: [PATCH] Make MarkupExtension.ProvideValue method inlinable for StaticResourceExtension and ResolveByNameExtension (#17659) --- .../ResolveByNameExtension.cs | 10 +++++++--- .../StaticResourceExtension.cs | 20 ++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs index db6e69f00fb..aaf0cb66f55 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using Avalonia.Controls; using Avalonia.Data.Core; @@ -13,14 +14,17 @@ public ResolveByNameExtension(string name) public string Name { get; } - public object? ProvideValue(IServiceProvider serviceProvider) + public object? ProvideValue(IServiceProvider serviceProvider) => ProvideValue(serviceProvider, Name); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static object? ProvideValue(IServiceProvider serviceProvider, string name) { var nameScope = serviceProvider.GetService(); if (nameScope is null) return null; - - var value = nameScope.FindAsync(Name); + + var value = nameScope.FindAsync(name); if(value.IsCompleted) return value.GetResult(); diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs index 6b048ef0d62..adc8ff7e580 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Runtime.CompilerServices; using Avalonia.Controls; using Avalonia.Markup.Data; using Avalonia.Markup.Xaml.Converters; @@ -22,9 +23,14 @@ public StaticResourceExtension(object resourceKey) public object? ResourceKey { get; set; } - public object? ProvideValue(IServiceProvider serviceProvider) + // Keep instance method ProvideValue as simple as possible, increasing chance to inline it. + // With modern runtimes, inlining this method also helps to eliminate extension allocation completely. + public object? ProvideValue(IServiceProvider serviceProvider) => ProvideValue(serviceProvider, ResourceKey); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static object? ProvideValue(IServiceProvider serviceProvider, object? resourceKey) { - if (ResourceKey is not { } resourceKey) + if (resourceKey is null) { throw new ArgumentException("StaticResourceExtension.ResourceKey must be set."); } @@ -87,20 +93,16 @@ public StaticResourceExtension(object resourceKey) { // This is stored locally to avoid allocating closure in the outer scope. var localTargetType = targetType; - var localInstance = this; + var localKeyInstance = resourceKey; - DelayedBinding.Add(target, property, x => localInstance.GetValue(x, localTargetType)); + DelayedBinding.Add(target, property, x => + ColorToBrushConverter.Convert(x.FindResource(localKeyInstance), localTargetType)); return AvaloniaProperty.UnsetValue; } throw new KeyNotFoundException($"Static resource '{resourceKey}' not found."); } - private object? GetValue(StyledElement control, Type? targetType) - { - return ColorToBrushConverter.Convert(control.FindResource(ResourceKey!), targetType); - } - internal static ThemeVariant? GetDictionaryVariant(IAvaloniaXamlIlParentStackProvider? stack) { switch (stack)