diff --git a/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs b/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs index 4fd668d463d70e..548398ae413d3c 100644 --- a/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs +++ b/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs @@ -7,12 +7,16 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; +#if NETFRAMEWORK || NETSTANDARD2_0 +using System.Runtime.Serialization; +#else +using System.Runtime.CompilerServices; +#endif + namespace Microsoft.Extensions.Internal { internal class ParameterDefaultValue { - private static readonly Type _nullable = typeof(Nullable<>); - public static bool TryGetDefaultValue(ParameterInfo parameter, out object? defaultValue) { bool hasDefaultValue; @@ -39,21 +43,27 @@ public static bool TryGetDefaultValue(ParameterInfo parameter, out object? defau defaultValue = parameter.DefaultValue; } + bool isNullableParameterType = parameter.ParameterType.IsGenericType && + parameter.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>); + // Workaround for https://github.com/dotnet/runtime/issues/18599 - if (defaultValue == null && parameter.ParameterType.IsValueType) + if (defaultValue == null && parameter.ParameterType.IsValueType + && !isNullableParameterType) // Nullable types should be left null { defaultValue = CreateValueType(parameter.ParameterType); } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern", - Justification = "CreateInstance is only called on a ValueType, which will always have a default constructor.")] - static object? CreateValueType(Type t) => Activator.CreateInstance(t); + Justification = "CreateValueType is only called on a ValueType. You can always create an instance of a ValueType.")] + static object? CreateValueType(Type t) => +#if NETFRAMEWORK || NETSTANDARD2_0 + FormatterServices.GetUninitializedObject(t); +#else + RuntimeHelpers.GetUninitializedObject(t); +#endif // Handle nullable enums - if (defaultValue != null && - parameter.ParameterType.IsGenericType && - parameter.ParameterType.GetGenericTypeDefinition() == _nullable - ) + if (defaultValue != null && isNullableParameterType) { Type? underlyingType = Nullable.GetUnderlyingType(parameter.ParameterType); if (underlyingType != null && underlyingType.IsEnum) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/Microsoft.Extensions.DependencyInjection.sln b/src/libraries/Microsoft.Extensions.DependencyInjection/Microsoft.Extensions.DependencyInjection.sln index 2a399d5f81104d..df87afddd220b5 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/Microsoft.Extensions.DependencyInjection.sln +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/Microsoft.Extensions.DependencyInjection.sln @@ -21,12 +21,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Win32.Registry", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\ref\System.Runtime.CompilerServices.Unsafe.csproj", "{7AA95B73-BE27-4E8C-AD7C-2E0F62B4E6BD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\src\System.Runtime.CompilerServices.Unsafe.ilproj", "{77D74FC2-FCB5-474B-AB77-2BD0354CEB29}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.CompilerServices.Unsafe", "..\System.Runtime.CompilerServices.Unsafe\src\System.Runtime.CompilerServices.Unsafe.ilproj", "{04BA3E3C-6979-4792-B19E-C797AD607F42}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Security.AccessControl", "..\System.Security.AccessControl\ref\System.Security.AccessControl.csproj", "{BA9F4FC9-6312-4E3D-BC54-300444064F6A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Security.Principal.Windows", "..\System.Security.Principal.Windows\ref\System.Security.Principal.Windows.csproj", "{B7FC8A33-9FB0-4E58-B3EC-06F4B95BF6D2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.TestStructs", "..\System.Runtime\tests\TestStructs\System.TestStructs.ilproj", "{6B002B34-089C-4BC4-91DD-57D350DEA91C}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C720B37D-E4D9-4B8C-B993-71F5C9C5A381}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D}" @@ -34,22 +36,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F109FFD1-2A08-4114-9FC5-A119229B4983}" EndProject Global - GlobalSection(NestedProjects) = preSolution - {30201F60-A891-4C3F-A1A6-DDDD1C8525E3} = {C720B37D-E4D9-4B8C-B993-71F5C9C5A381} - {F11DD75C-122C-4B98-9EED-F71551F9562A} = {C720B37D-E4D9-4B8C-B993-71F5C9C5A381} - {1EE6CA66-6585-459D-8889-666D4C2D4C27} = {C720B37D-E4D9-4B8C-B993-71F5C9C5A381} - {047FD3F2-B3A0-4639-B4F0-40D29E61725D} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} - {6D90C067-5CCD-4443-81A5-B9C385011F68} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} - {66E6ADF5-200F-41F3-9CA4-858EF69D2A61} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} - {FE84DBDF-2275-4B14-8B08-A59A64E573BA} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} - {7AA95B73-BE27-4E8C-AD7C-2E0F62B4E6BD} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} - {BA9F4FC9-6312-4E3D-BC54-300444064F6A} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} - {B7FC8A33-9FB0-4E58-B3EC-06F4B95BF6D2} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} - {3068B34E-D975-4C11-B2F2-F10790051F2E} = {F109FFD1-2A08-4114-9FC5-A119229B4983} - {9CD9F9EB-379C-44C1-9016-33DFEC821C76} = {F109FFD1-2A08-4114-9FC5-A119229B4983} - {C5ECD02C-FA5A-4B56-9CA2-47AD8989714A} = {F109FFD1-2A08-4114-9FC5-A119229B4983} - {77D74FC2-FCB5-474B-AB77-2BD0354CEB29} = {F109FFD1-2A08-4114-9FC5-A119229B4983} - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -99,10 +85,10 @@ Global {7AA95B73-BE27-4E8C-AD7C-2E0F62B4E6BD}.Debug|Any CPU.Build.0 = Debug|Any CPU {7AA95B73-BE27-4E8C-AD7C-2E0F62B4E6BD}.Release|Any CPU.ActiveCfg = Release|Any CPU {7AA95B73-BE27-4E8C-AD7C-2E0F62B4E6BD}.Release|Any CPU.Build.0 = Release|Any CPU - {77D74FC2-FCB5-474B-AB77-2BD0354CEB29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77D74FC2-FCB5-474B-AB77-2BD0354CEB29}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77D74FC2-FCB5-474B-AB77-2BD0354CEB29}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77D74FC2-FCB5-474B-AB77-2BD0354CEB29}.Release|Any CPU.Build.0 = Release|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04BA3E3C-6979-4792-B19E-C797AD607F42}.Release|Any CPU.Build.0 = Release|Any CPU {BA9F4FC9-6312-4E3D-BC54-300444064F6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BA9F4FC9-6312-4E3D-BC54-300444064F6A}.Debug|Any CPU.Build.0 = Debug|Any CPU {BA9F4FC9-6312-4E3D-BC54-300444064F6A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -111,10 +97,31 @@ Global {B7FC8A33-9FB0-4E58-B3EC-06F4B95BF6D2}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7FC8A33-9FB0-4E58-B3EC-06F4B95BF6D2}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7FC8A33-9FB0-4E58-B3EC-06F4B95BF6D2}.Release|Any CPU.Build.0 = Release|Any CPU + {6B002B34-089C-4BC4-91DD-57D350DEA91C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B002B34-089C-4BC4-91DD-57D350DEA91C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B002B34-089C-4BC4-91DD-57D350DEA91C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B002B34-089C-4BC4-91DD-57D350DEA91C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {30201F60-A891-4C3F-A1A6-DDDD1C8525E3} = {C720B37D-E4D9-4B8C-B993-71F5C9C5A381} + {047FD3F2-B3A0-4639-B4F0-40D29E61725D} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} + {3068B34E-D975-4C11-B2F2-F10790051F2E} = {F109FFD1-2A08-4114-9FC5-A119229B4983} + {6D90C067-5CCD-4443-81A5-B9C385011F68} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} + {9CD9F9EB-379C-44C1-9016-33DFEC821C76} = {F109FFD1-2A08-4114-9FC5-A119229B4983} + {66E6ADF5-200F-41F3-9CA4-858EF69D2A61} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} + {C5ECD02C-FA5A-4B56-9CA2-47AD8989714A} = {F109FFD1-2A08-4114-9FC5-A119229B4983} + {F11DD75C-122C-4B98-9EED-F71551F9562A} = {C720B37D-E4D9-4B8C-B993-71F5C9C5A381} + {1EE6CA66-6585-459D-8889-666D4C2D4C27} = {C720B37D-E4D9-4B8C-B993-71F5C9C5A381} + {FE84DBDF-2275-4B14-8B08-A59A64E573BA} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} + {7AA95B73-BE27-4E8C-AD7C-2E0F62B4E6BD} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} + {04BA3E3C-6979-4792-B19E-C797AD607F42} = {F109FFD1-2A08-4114-9FC5-A119229B4983} + {BA9F4FC9-6312-4E3D-BC54-300444064F6A} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} + {B7FC8A33-9FB0-4E58-B3EC-06F4B95BF6D2} = {3C9BFC55-DE9A-42C0-A843-2F7D703EEB7D} + {6B002B34-089C-4BC4-91DD-57D350DEA91C} = {C720B37D-E4D9-4B8C-B993-71F5C9C5A381} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {68A7BDA7-8093-433C-BF7A-8A6A7560BD02} EndGlobalSection diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Microsoft.Extensions.DependencyInjection.ExternalContainers.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Microsoft.Extensions.DependencyInjection.ExternalContainers.Tests.csproj index 1231ca958ed36f..c49d2d7804f9e9 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Microsoft.Extensions.DependencyInjection.ExternalContainers.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Microsoft.Extensions.DependencyInjection.ExternalContainers.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);net461 @@ -18,6 +18,7 @@ + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Unity.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Unity.cs index ab41baf4510c62..affa7de4551afd 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Unity.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Unity.cs @@ -7,6 +7,9 @@ namespace Microsoft.Extensions.DependencyInjection.Specification { public class UnityDependencyInjectionSpecificationTests: SkippableDependencyInjectionSpecificationTests { + // See https://github.com/unitycontainer/microsoft-dependency-injection/issues/87 + public override bool ExpectStructWithPublicDefaultConstructorInvoked => true; + public override string[] SkippedTests => new[] { "SingletonServiceCanBeResolvedFromScope" diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs index 73ce408fddcc3a..4d2f11747a7fe4 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs @@ -12,6 +12,9 @@ namespace Microsoft.Extensions.DependencyInjection.Specification [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public abstract partial class DependencyInjectionSpecificationTests { + // for most DI providers, the structs default constructor shouldn't run when creating an instance of ClassWithOptionalArgsCtorWithStructs + public virtual bool ExpectStructWithPublicDefaultConstructorInvoked => false; + public delegate object CreateInstanceFunc(IServiceProvider provider, Type type, object[] args); private static object CreateInstanceDirectly(IServiceProvider provider, Type type, object[] args) @@ -117,6 +120,7 @@ public void TypeActivatorWorksWithCtorWithOptionalArgs_WithStructDefaults(Create Assert.Null(anotherClass.ColorNull); Assert.Equal(12, anotherClass.Integer); Assert.Null(anotherClass.IntegerNull); + Assert.Equal(ExpectStructWithPublicDefaultConstructorInvoked, anotherClass.StructWithConstructor.ConstructorInvoked); } [Theory] diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs index 7e9e4dcede70bd..2693c4580ecf66 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Tests; namespace Microsoft.Extensions.DependencyInjection.Specification { @@ -13,6 +14,8 @@ public class ClassWithOptionalArgsCtorWithStructs public int? Integer { get; } public int? IntegerNull { get; } + public StructWithPublicDefaultConstructor StructWithConstructor { get; } + public ClassWithOptionalArgsCtorWithStructs( DateTime dateTime = new DateTime(), DateTime dateTimeDefault = default(DateTime), @@ -27,13 +30,15 @@ public ClassWithOptionalArgsCtorWithStructs( ConsoleColor? color = ConsoleColor.DarkGreen, ConsoleColor? colorNull = null, int? integer = 12, - int? integerNull = null + int? integerNull = null, + StructWithPublicDefaultConstructor structWithConstructor = default ) { Color = color; ColorNull = colorNull; Integer = integer; IntegerNull = integerNull; + StructWithConstructor = structWithConstructor; } public struct CustomStruct { } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj index bb3a008f3684dc..18ceaac11e4230 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj @@ -14,6 +14,7 @@ +