From 2b89eae59ef7b833e59cf1f8791443f9dbdbba47 Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Thu, 16 Oct 2025 15:56:36 +0100 Subject: [PATCH 01/16] Update to .NET 10 and C# 14 --- Directory.Build.props | 2 +- build/Base.props | 6 ++-- build/TargetFrameworks.props | 14 +++++----- build/UnitTests.NetCore.targets | 5 +--- build/XUnit.props | 2 +- external/XamlX | 2 +- global.json | 2 +- nukebuild/Build.cs | 4 +-- packages/Avalonia/AvaloniaPrivateApis.targets | 2 +- .../ControlCatalog.Android.csproj | 2 +- .../ControlCatalog.Browser.Blazor.csproj | 4 +-- samples/Directory.Build.props | 2 +- samples/XEmbedSample/XEmbedSample.csproj | 28 +++++++++---------- .../Avalonia.Android/Avalonia.Android.csproj | 4 +-- .../Data/Core/BindingExpression.cs | 3 ++ .../Reflection/DynamicPluginStreamNode.cs | 3 ++ .../Reflection/ExpressionTreeIndexerNode.cs | 3 ++ .../Core/Parsers/BindingExpressionVisitor.cs | 3 ++ .../Data/Core/Plugins/BindingPlugins.cs | 1 + .../Plugins/ReflectionMethodAccessorPlugin.cs | 6 ++++ .../Diagnostics/TrimmingMessages.cs | 4 +++ .../Expressions/ExpressionParser.cs | 2 +- src/Avalonia.Base/Utilities/Polyfills.cs | 6 ++-- .../Avalonia.Build.Tasks.csproj | 1 + .../AvaloniaNativeGlPlatformGraphics.cs | 4 ++- src/Avalonia.Native/Metal.cs | 4 ++- .../Avalonia.Remote.Protocol.csproj | 1 + src/Avalonia.Remote.Protocol/MetsysBson.cs | 14 +++++++++- .../Avalonia.Browser.Blazor.csproj | 2 +- .../Avalonia.Markup.Xaml.Loader.csproj | 5 ++++ .../AvaloniaXamlIlLanguage.cs | 4 +++ .../AvaloniaXamlIlQueryTransformer.cs | 4 +++ .../AvaloniaXamlIlSelectorTransformer.cs | 3 ++ .../AvaloniaXamlIlWellKnownTypes.cs | 2 ++ .../XamlIlBindingPathHelper.cs | 8 ++++++ ...amlIlPropertyInfoAccessorFactoryEmitter.cs | 5 ++++ .../IncludeXamlIlSre.props | 2 +- .../ReflectionBindingExtension.cs | 3 ++ .../Templates/TreeDataTemplate.cs | 1 + .../XamlIl/Runtime/XamlIlRuntimeHelpers.cs | 2 +- src/Markup/Avalonia.Markup/Data/Binding.cs | 6 ++++ .../Markup/Parsers/ExpressionNodeFactory.cs | 3 ++ .../WinForms/WinFormsAvaloniaControlHost.cs | 1 + .../Avalonia.Win32/Avalonia.Win32.csproj | 4 +-- src/iOS/Avalonia.iOS/AvaloniaAppDelegate.cs | 2 +- src/iOS/Avalonia.iOS/IOSLauncher.cs | 2 +- src/iOS/Avalonia.iOS/iOSScreens.cs | 2 +- .../Avalonia.Designer.HostApp.csproj | 1 + .../CompilerDynamicDependenciesGenerator.cs | 28 +++++++++++++------ .../Avalonia.Headless.NUnit.UnitTests.csproj | 2 +- .../Avalonia.LeakTests.csproj | 2 +- .../Avalonia.UnitTests.csproj | 2 +- 52 files changed, 162 insertions(+), 68 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index f124456eab1..c6ed387d66a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,7 +8,7 @@ false False - 12 + 14.0 true true true diff --git a/build/Base.props b/build/Base.props index 0e667f105b9..1c618dfcd67 100644 --- a/build/Base.props +++ b/build/Base.props @@ -1,12 +1,12 @@  - + - + - + diff --git a/build/TargetFrameworks.props b/build/TargetFrameworks.props index f14a3876fff..4be557a59b3 100644 --- a/build/TargetFrameworks.props +++ b/build/TargetFrameworks.props @@ -1,17 +1,17 @@ - net8.0 + net10.0 $(AvsCurrentTargetFramework)-windows $(AvsCurrentTargetFramework)-macos - $(AvsCurrentTargetFramework)-android34.0 - $(AvsCurrentTargetFramework)-maccatalyst17.0 - $(AvsCurrentTargetFramework)-ios17.0 - $(AvsCurrentTargetFramework)-tvos17.0 + $(AvsCurrentTargetFramework)-android36.0 + $(AvsCurrentTargetFramework)-maccatalyst26.0 + $(AvsCurrentTargetFramework)-ios26.0 + $(AvsCurrentTargetFramework)-tvos26.0 $(AvsCurrentTargetFramework)-browser - net6.0 - net6.0-windows + net8.0 + net8.0-windows diff --git a/build/UnitTests.NetCore.targets b/build/UnitTests.NetCore.targets index 42da8e4ab17..19b2253f4ff 100644 --- a/build/UnitTests.NetCore.targets +++ b/build/UnitTests.NetCore.targets @@ -3,7 +3,4 @@ false true - - - - \ No newline at end of file + diff --git a/build/XUnit.props b/build/XUnit.props index b4e9708ecde..4b00869d5b6 100644 --- a/build/XUnit.props +++ b/build/XUnit.props @@ -8,7 +8,7 @@ - + $(MSBuildThisFileDirectory)\avalonia.snk diff --git a/external/XamlX b/external/XamlX index 83567b8a50b..99a49740bd6 160000 --- a/external/XamlX +++ b/external/XamlX @@ -1 +1 @@ -Subproject commit 83567b8a50bbf612a0b1420a3dc6d8e8ebee2399 +Subproject commit 99a49740bd6a587b1852337764741ec280e201d6 diff --git a/global.json b/global.json index f496cffc503..7fed696458a 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.411", + "version": "10.0.100-rc.2.25502.107", "rollForward": "latestFeature" }, "msbuild-sdks": { diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index b0d8106d325..c7e8b776f76 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -240,11 +240,11 @@ void RunCoreTest(string projectName, Action runTest) var tfm = fw; if (tfm == "$(AvsCurrentTargetFramework)") { - tfm = "net8.0"; + tfm = "net10.0"; } if (tfm == "$(AvsLegacyTargetFrameworks)") { - tfm = "net6.0"; + tfm = "net8.0"; } if (tfm.StartsWith("net4") diff --git a/packages/Avalonia/AvaloniaPrivateApis.targets b/packages/Avalonia/AvaloniaPrivateApis.targets index 5f69187d923..47219535cc9 100644 --- a/packages/Avalonia/AvaloniaPrivateApis.targets +++ b/packages/Avalonia/AvaloniaPrivateApis.targets @@ -13,7 +13,7 @@ - net6.0 + net8.0 netstandard2.0 diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 958725eed5b..f60ba69395e 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -26,7 +26,7 @@ - + diff --git a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj b/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj index 2950028e687..763ab26cabf 100644 --- a/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj +++ b/samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index 3a61d3fff97..169239237f1 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -4,7 +4,7 @@ false $(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\netstandard2.0\Avalonia.Designer.HostApp.dll false - 12 + 14.0 $(NoWarn);CS8002 diff --git a/samples/XEmbedSample/XEmbedSample.csproj b/samples/XEmbedSample/XEmbedSample.csproj index 01ea7432db0..a6e754692db 100644 --- a/samples/XEmbedSample/XEmbedSample.csproj +++ b/samples/XEmbedSample/XEmbedSample.csproj @@ -1,20 +1,20 @@ - - Exe - net6.0 - enable - enable - true - + + Exe + $(AvsCurrentTargetFramework) + enable + enable + true + - - - + + + - - - - + + + + diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 2fb849ee0de..4dc8d3113e3 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Avalonia.Base/Data/Core/BindingExpression.cs b/src/Avalonia.Base/Data/Core/BindingExpression.cs index ca29dd6ffa4..a51ee5bf8a5 100644 --- a/src/Avalonia.Base/Data/Core/BindingExpression.cs +++ b/src/Avalonia.Base/Data/Core/BindingExpression.cs @@ -190,6 +190,9 @@ public override void UpdateTarget() /// The null target value. /// Whether to allow reflection for target type conversion. [RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal static BindingExpression Create( TIn source, Expression> expression, diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs index f6c692e6859..dd8c0e1a63d 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/DynamicPluginStreamNode.cs @@ -7,6 +7,9 @@ namespace Avalonia.Data.Core.ExpressionNodes.Reflection; [RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER +[RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal sealed class DynamicPluginStreamNode : ExpressionNode { private IDisposable? _subscription; diff --git a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs index e720aa6e693..dfb83fb10d9 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNodes/Reflection/ExpressionTreeIndexerNode.cs @@ -16,6 +16,9 @@ internal sealed class ExpressionTreeIndexerNode : CollectionNodeBase, ISettableN private readonly Delegate _getDelegate; private readonly Delegate _firstArgumentDelegate; +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif public ExpressionTreeIndexerNode(IndexExpression expression) { var valueParameter = Expression.Parameter(expression.Type); diff --git a/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs b/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs index 39d6ffcab66..19817321451 100644 --- a/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs +++ b/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionVisitor.cs @@ -11,6 +11,9 @@ namespace Avalonia.Data.Core.Parsers; [RequiresUnreferencedCode(TrimmingMessages.ExpressionNodeRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER +[RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal class BindingExpressionVisitor : ExpressionVisitor { private static readonly PropertyInfo AvaloniaObjectIndexer; diff --git a/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs b/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs index 5c2d9aaddf5..520c345ad5f 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/BindingPlugins.cs @@ -28,6 +28,7 @@ public static class BindingPlugins new ObservableStreamPlugin(), }; + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "We're checking if dynamic code is supported.")] static BindingPlugins() { // When building with AOT, don't create ReflectionMethodAccessorPlugin instance. diff --git a/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs index e295fc60669..f9a4587ca63 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/ReflectionMethodAccessorPlugin.cs @@ -7,6 +7,9 @@ namespace Avalonia.Data.Core.Plugins { [RequiresUnreferencedCode(TrimmingMessages.PropertyAccessorsRequiresUnreferencedCodeMessage)] +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif internal class ReflectionMethodAccessorPlugin : IPropertyAccessorPlugin { private readonly Dictionary<(Type, string), MethodInfo?> _methodLookup = @@ -81,6 +84,9 @@ internal class ReflectionMethodAccessorPlugin : IPropertyAccessorPlugin return found; } +#if NET8_0_OR_GREATER + [RequiresDynamicCode(TrimmingMessages.ExpressionNodeRequiresDynamicCodeMessage)] +#endif private sealed class Accessor : PropertyAccessorBase { public Accessor(WeakReference reference, MethodInfo method) diff --git a/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs b/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs index ce9c9e187b7..930ff4202bc 100644 --- a/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs +++ b/src/Avalonia.Base/Diagnostics/TrimmingMessages.cs @@ -9,11 +9,13 @@ internal static class TrimmingMessages public const string TypeConversionRequiresUnreferencedCodeMessage = "Conversion methods are required for type conversion, including op_Implicit, op_Explicit, Parse and TypeConverter."; public const string ReflectionBindingRequiresUnreferencedCodeMessage = "BindingExpression and ReflectionBinding heavily use reflection. Consider using CompiledBindings instead."; + public const string ReflectionBindingRequiresDynamicCodeMessage = "BindingExpression and ReflectionBinding require dynamic code. Consider using CompiledBindings instead."; public const string ReflectionBindingSupressWarningMessage = "BindingExpression and ReflectionBinding internal heavily use reflection."; public const string CompiledBindingSafeSupressWarningMessage = "CompiledBinding preserves members used in the expression tree."; public const string ExpressionNodeRequiresUnreferencedCodeMessage = "ExpressionNode might require unreferenced code."; + public const string ExpressionNodeRequiresDynamicCodeMessage = "ExpressionNode requires dynamic code."; public const string ExpressionSafeSupressWarningMessage = "Typed Expressions preserves members used in the expression tree."; public const string SelectorsParseRequiresUnreferencedCodeMessage = "Selectors runtime parser might require unreferenced code. Consider using stronly typed selectors factory with 'new Style(s => s.OfType