diff --git a/dotnet/SK-dotnet.sln b/dotnet/SK-dotnet.sln index dd033335580e..225fa663eeea 100644 --- a/dotnet/SK-dotnet.sln +++ b/dotnet/SK-dotnet.sln @@ -108,15 +108,15 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Diagnostics", "Diagnostics", "{29E7D971-1308-4171-9872-E8E4669A1134}" ProjectSection(SolutionItems) = preProject src\InternalUtilities\src\Diagnostics\CompilerServicesAttributes.cs = src\InternalUtilities\src\Diagnostics\CompilerServicesAttributes.cs + src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs = src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs src\InternalUtilities\src\Diagnostics\ExceptionExtensions.cs = src\InternalUtilities\src\Diagnostics\ExceptionExtensions.cs src\InternalUtilities\src\Diagnostics\ExperimentalAttribute.cs = src\InternalUtilities\src\Diagnostics\ExperimentalAttribute.cs src\InternalUtilities\src\Diagnostics\IsExternalInit.cs = src\InternalUtilities\src\Diagnostics\IsExternalInit.cs src\InternalUtilities\src\Diagnostics\NullableAttributes.cs = src\InternalUtilities\src\Diagnostics\NullableAttributes.cs - src\InternalUtilities\src\Diagnostics\Verify.cs = src\InternalUtilities\src\Diagnostics\Verify.cs - src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs = src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs src\InternalUtilities\src\Diagnostics\RequiresDynamicCodeAttribute.cs = src\InternalUtilities\src\Diagnostics\RequiresDynamicCodeAttribute.cs src\InternalUtilities\src\Diagnostics\RequiresUnreferencedCodeAttribute.cs = src\InternalUtilities\src\Diagnostics\RequiresUnreferencedCodeAttribute.cs src\InternalUtilities\src\Diagnostics\UnconditionalSuppressMessageAttribute.cs = src\InternalUtilities\src\Diagnostics\UnconditionalSuppressMessageAttribute.cs + src\InternalUtilities\src\Diagnostics\Verify.cs = src\InternalUtilities\src\Diagnostics\Verify.cs EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linq", "Linq", "{B00AD427-0047-4850-BEF9-BA8237EA9D8B}" @@ -364,7 +364,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Process.LocalRuntime", "src EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Process.UnitTests", "src\Experimental\Process.UnitTests\Process.UnitTests.csproj", "{21A32285-8443-4A75-B2E8-27E6090EC562}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GettingStartedWithProcesses", "samples\GettingStartedWithProcesses\GettingStartedWithProcesses.csproj", "{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GettingStartedWithProcesses", "samples\GettingStartedWithProcesses\GettingStartedWithProcesses.csproj", "{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AotCompatibility.TestApp", "samples\Demos\AotCompatibility.TestApp\AotCompatibility.TestApp.csproj", "{6ECFDF04-2237-4A85-B114-DAA34923E9E6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -931,6 +933,12 @@ Global {C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}.Publish|Any CPU.Build.0 = Debug|Any CPU {C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}.Release|Any CPU.ActiveCfg = Release|Any CPU {C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}.Release|Any CPU.Build.0 = Release|Any CPU + {6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Publish|Any CPU.ActiveCfg = Publish|Any CPU + {6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Publish|Any CPU.Build.0 = Publish|Any CPU + {6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1059,8 +1067,9 @@ Global {27AF60D6-86F5-4591-A700-4F8C93F41B11} = {0D8C6358-5DAA-4EA6-A924-C268A9A21BC9} {21A32285-8443-4A75-B2E8-27E6090EC562} = {0D8C6358-5DAA-4EA6-A924-C268A9A21BC9} {C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7} = {FA3720F1-C99A-49B2-9577-A940257098BF} + {6ECFDF04-2237-4A85-B114-DAA34923E9E6} = {5D4C0700-BBB5-418F-A7B2-F392B9A18263} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FBDC56A3-86AD-4323-AA0F-201E59123B83} EndGlobalSection -EndGlobal \ No newline at end of file +EndGlobal diff --git a/dotnet/samples/Demos/AotCompatibility.TestApp/AotCompatibility.TestApp.csproj b/dotnet/samples/Demos/AotCompatibility.TestApp/AotCompatibility.TestApp.csproj new file mode 100644 index 000000000000..0a821a1eb48f --- /dev/null +++ b/dotnet/samples/Demos/AotCompatibility.TestApp/AotCompatibility.TestApp.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + enable + enable + true + false + + + + + + + diff --git a/dotnet/samples/Demos/AotCompatibility.TestApp/Program.cs b/dotnet/samples/Demos/AotCompatibility.TestApp/Program.cs new file mode 100644 index 000000000000..ce9dab0164c2 --- /dev/null +++ b/dotnet/samples/Demos/AotCompatibility.TestApp/Program.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. + +namespace AotCompatibility.TestApp; + +internal static class Program +{ + private static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } +} diff --git a/dotnet/src/InternalUtilities/src/System/InternalTypeConverter.cs b/dotnet/src/InternalUtilities/src/System/InternalTypeConverter.cs index e613a9af7684..e209fe190e15 100644 --- a/dotnet/src/InternalUtilities/src/System/InternalTypeConverter.cs +++ b/dotnet/src/InternalUtilities/src/System/InternalTypeConverter.cs @@ -38,17 +38,19 @@ internal static class InternalTypeConverter /// /// The source Type for which to retrieve the type-to-string converter delegate. /// A Func delegate for converting the source type to a string, considering CultureInfo, or null if no suitable converter is found. - private static Func? GetTypeToStringConverterDelegate(Type sourceType) => - s_converters.GetOrAdd(sourceType, static sourceType => + private static Func? GetTypeToStringConverterDelegate( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] Type sourceType) => + s_converters.GetOrAdd(sourceType, ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] Type innerSourceType) => { // Strings just render as themselves. - if (sourceType == typeof(string)) + if (innerSourceType == typeof(string)) { return (input, cultureInfo) => (string)input!; } // Look up and use a type converter. - if (TypeConverterFactory.GetTypeConverter(sourceType) is TypeConverter converter && converter.CanConvertTo(typeof(string))) + if (TypeConverterFactory.GetTypeConverter(innerSourceType) is TypeConverter converter && converter.CanConvertTo(typeof(string))) { return (input, cultureInfo) => { diff --git a/dotnet/src/InternalUtilities/src/System/TypeConverterFactory.cs b/dotnet/src/InternalUtilities/src/System/TypeConverterFactory.cs index 2049dda894af..e9cff09ca633 100644 --- a/dotnet/src/InternalUtilities/src/System/TypeConverterFactory.cs +++ b/dotnet/src/InternalUtilities/src/System/TypeConverterFactory.cs @@ -18,7 +18,8 @@ internal static class TypeConverterFactory /// /// The Type of the object to convert. /// A TypeConverter instance if a suitable converter is found, otherwise null. - internal static TypeConverter? GetTypeConverter(Type type) + internal static TypeConverter? GetTypeConverter( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] Type type) { // In an ideal world, this would use TypeDescriptor.GetConverter. However, that is not friendly to // any form of ahead-of-time compilation, as it could end up requiring functionality that was trimmed. diff --git a/dotnet/src/SemanticKernel.Abstractions/Services/EmptyServiceProvider.cs b/dotnet/src/SemanticKernel.Abstractions/Services/EmptyServiceProvider.cs index 4328d6041023..08305ca9df83 100644 --- a/dotnet/src/SemanticKernel.Abstractions/Services/EmptyServiceProvider.cs +++ b/dotnet/src/SemanticKernel.Abstractions/Services/EmptyServiceProvider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.SemanticKernel; @@ -32,9 +33,29 @@ public object GetRequiredKeyedService(Type serviceType, object? serviceKey) => if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { - return Array.CreateInstance(serviceType.GenericTypeArguments[0], 0); + return CreateArray(serviceType.GenericTypeArguments[0], 0); } return null; } + + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "VerifyAotCompatibility ensures elementType is not a ValueType")] + private static Array CreateArray(Type elementType, int length) + { + if (VerifyAotCompatibility && elementType.IsValueType) + { + // NativeAOT apps are not able to make Enumerable of ValueType services + // since there is no guarantee the ValueType[] code has been generated. + throw new InvalidOperationException($"Unable to create an Enumerable service of type '{elementType}' because it is a ValueType. Native code to support creating Enumerable services might not be available with native AOT."); + } + + return Array.CreateInstance(elementType, length); + } + + private static bool VerifyAotCompatibility => +#if NETFRAMEWORK || NETSTANDARD2_0 + false; +#else + !System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported; +#endif }