ソースを参照

Make MarkupExtension.ProvideValue method inlinable for StaticResourceExtension and ResolveByNameExtension (#17659)

Max Katz 11 ヶ月 前
コミット
a530bbeb99

+ 7 - 3
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 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         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<INameScope>();
 
             if (nameScope is null)
                 return null;
-            
-            var value = nameScope.FindAsync(Name);
+
+            var value = nameScope.FindAsync(name);
 
             if(value.IsCompleted)
                 return value.GetResult();

+ 11 - 9
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 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         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 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
             {
                 // 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)