diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs index 71cc9d81b2c..5cb5316b1ca 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -76,7 +76,7 @@ public static (XamlLanguageTypeMappings language, XamlLanguageEmitMappings { EmitNameScopeField(rv, typeSystem, definition); - EmitEagerParentStackProvider(rv, typeSystem, definition); + EmitEagerParentStackProvider(rv, typeSystem, definition, runtimeHelpers); } }; return (rv, emit); @@ -104,7 +104,8 @@ private static void EmitNameScopeField( private static void EmitEagerParentStackProvider( XamlLanguageTypeMappings mappings, IXamlTypeSystem typeSystem, - IXamlILContextDefinition definition) + IXamlILContextDefinition definition, + IXamlType runtimeHelpers) { var interfaceType = typeSystem.FindType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlEagerParentStackProvider"); @@ -122,14 +123,22 @@ private static void EmitEagerParentStackProvider( typeSystem.FindType("System.Object"), typeSystem.FindType("System.Type"))); + var asEagerParentStackProviderMethod = runtimeHelpers.GetMethod(new FindMethodMethodSignature( + "AsEagerParentStackProvider", + interfaceType, + mappings.ParentStackProvider) + { + IsStatic = true + }); + // IAvaloniaXamlIlEagerParentStackProvider? ParentProvider - // => (IAvaloniaXamlIlEagerParentStackProvider)_serviceProvider.GetService(typeof(IAvaloniaXamlIlParentStackProvider)) + // => XamlIlRuntimeHelpers.AsEagerParentStackProvider(_serviceProvider.GetService(typeof(IAvaloniaXamlIlParentStackProvider))); var parentProviderGetter = ImplementInterfacePropertyGetter("ParentProvider"); parentProviderGetter.Generator .LdThisFld(definition.ParentServiceProviderField) .Ldtype(mappings.ParentStackProvider) .EmitCall(serviceProviderGetServiceMethod) - .Castclass(interfaceType) + .EmitCall(asEagerParentStackProviderMethod) .Ret(); IXamlMethodBuilder ImplementInterfacePropertyGetter(string propertyName) diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 28911562e68..4b9e608f5c4 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -52,6 +52,7 @@ + diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlParentStackProviderWrapper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlParentStackProviderWrapper.cs new file mode 100644 index 00000000000..60856d2b20b --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlParentStackProviderWrapper.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Avalonia.Markup.Xaml.XamlIl.Runtime; + +/// +/// Wraps a into a , +/// for backwards compatibility. +/// +internal sealed class XamlIlParentStackProviderWrapper : IAvaloniaXamlIlEagerParentStackProvider +{ + private readonly IAvaloniaXamlIlParentStackProvider _provider; + + private IReadOnlyList? _directParentsStack; + + public XamlIlParentStackProviderWrapper(IAvaloniaXamlIlParentStackProvider provider) + => _provider = provider; + + public IEnumerable Parents + => _provider.Parents; + + public IReadOnlyList DirectParentsStack + => _directParentsStack ??= _provider.Parents.Reverse().ToArray(); + + public IAvaloniaXamlIlEagerParentStackProvider? ParentProvider + => null; +} diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs index 79c56cb351b..d7c8003b2b9 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs @@ -95,6 +95,14 @@ private static IResourceNode[] AsResourceNodesStack(IAvaloniaXamlIlParentStackPr return resourceNodes; } + /// + /// Converts a into a + /// . + /// + public static IAvaloniaXamlIlEagerParentStackProvider AsEagerParentStackProvider( + this IAvaloniaXamlIlParentStackProvider provider) + => provider as IAvaloniaXamlIlEagerParentStackProvider ?? new XamlIlParentStackProviderWrapper(provider); + // Parent resource nodes are often the same (e.g. most values in a ResourceDictionary), cache the last ones. private sealed class LastParentStack {