From 8bd9571ad705d9d5db60d2daa596967ca54024e7 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Thu, 17 Aug 2023 16:29:46 -0700 Subject: [PATCH] Fix polymorphic issue and address feedback --- .../src/SourceGenerators/GeneratorHelpers.cs | 12 -- .../ConfigurationBindingGenerator.Emitter.cs | 14 +- .../ConfigurationBindingGenerator.Parser.cs | 48 ++++- ...onfigurationBindingGenerator.Suppressor.cs | 12 +- .../gen/ConfigurationBindingGenerator.cs | 12 +- .../Helpers/Emitter/ConfigurationBinder.cs | 58 ++++-- .../gen/Helpers/Emitter/CoreBindingHelpers.cs | 112 +++++------ .../gen/Helpers/Emitter/Helpers.cs | 31 +++- .../OptionsBuilderConfigurationExtensions.cs | 5 +- ...onfigurationServiceCollectionExtensions.cs | 2 +- .../gen/Helpers/InterceptorLocationInfo.cs | 54 +++++- .../gen/Helpers/MethodsToGen.cs | 6 +- .../gen/Helpers/Parser/ConfigurationBinder.cs | 25 ++- .../OptionsBuilderConfigurationExtensions.cs | 10 +- ...onfigurationServiceCollectionExtensions.cs | 4 +- ...nfiguration.Binder.SourceGeneration.csproj | 1 - .../gen/Model/ObjectSpec.cs | 4 - .../gen/Model/SourceGenerationSpec.cs | 4 +- .../gen/Resources/Strings.resx | 4 +- .../gen/Resources/xlf/Strings.cs.xlf | 8 +- .../gen/Resources/xlf/Strings.de.xlf | 8 +- .../gen/Resources/xlf/Strings.es.xlf | 8 +- .../gen/Resources/xlf/Strings.fr.xlf | 8 +- .../gen/Resources/xlf/Strings.it.xlf | 8 +- .../gen/Resources/xlf/Strings.ja.xlf | 8 +- .../gen/Resources/xlf/Strings.ko.xlf | 8 +- .../gen/Resources/xlf/Strings.pl.xlf | 8 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 8 +- .../gen/Resources/xlf/Strings.ru.xlf | 8 +- .../gen/Resources/xlf/Strings.tr.xlf | 8 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 8 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 8 +- .../tests/Common/ConfigurationBinderTests.cs | 6 +- .../Baselines/Collections.generated.txt | 164 +++-------------- .../ConfigurationBinder/Bind.generated.txt | 126 +++++-------- .../Bind_Instance.generated.txt | 128 +++---------- .../Bind_Instance_BinderOptions.generated.txt | 110 +++-------- .../Bind_Key_Instance.generated.txt | 128 +++---------- .../ConfigurationBinder/Get.generated.txt | 129 +++---------- .../GetValue.generated.txt | 9 +- .../ConfigurationBinder/Get_T.generated.txt | 111 +++-------- .../Get_T_BinderOptions.generated.txt | 111 +++-------- .../Get_TypeOf.generated.txt | 40 +--- .../Get_TypeOf_BinderOptions.generated.txt | 40 +--- .../BindConfiguration.generated.txt | 54 +++--- .../OptionsBuilder/Bind_T.generated.txt | 44 ++--- .../Bind_T_BinderOptions.generated.txt | 44 ++--- .../Baselines/Primitives.generated.txt | 174 ++++++------------ .../Configure_T.generated.txt | 101 +++------- .../Configure_T_BinderOptions.generated.txt | 101 +++------- .../Configure_T_name.generated.txt | 101 +++------- ...nfigure_T_name_BinderOptions.generated.txt | 101 +++------- .../ConfigurationBindingGeneratorTests.cs | 10 +- ...ft.Extensions.Logging.Configuration.csproj | 1 - ...icrosoft.Extensions.Logging.Console.csproj | 2 +- .../gen/Emitter.cs | 8 +- ...Extensions.Options.SourceGeneration.csproj | 1 - 57 files changed, 784 insertions(+), 1582 deletions(-) delete mode 100644 src/libraries/Common/src/SourceGenerators/GeneratorHelpers.cs diff --git a/src/libraries/Common/src/SourceGenerators/GeneratorHelpers.cs b/src/libraries/Common/src/SourceGenerators/GeneratorHelpers.cs deleted file mode 100644 index 1ec1d1883302c..0000000000000 --- a/src/libraries/Common/src/SourceGenerators/GeneratorHelpers.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace SourceGenerators -{ - public static class GeneratorHelpers - { - public static string MakeNameUnique(ref string name) => name += $"_{new Random().Next():X8}"; - } -} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs index 351c211c6c18a..756e10bc26b8d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs @@ -17,7 +17,6 @@ private sealed partial class Emitter private readonly SourceProductionContext _context; private readonly SourceGenerationSpec _sourceGenSpec; - private readonly string _generatedNamespaceName = ProjectName; private bool _emitBlankLineBeforeNextStatement; private int _valueSuffixIndex; @@ -25,15 +24,10 @@ private sealed partial class Emitter private readonly SourceWriter _writer = new(); - public Emitter(SourceProductionContext context, SourceGenerationSpec sourceGenSpec, bool emitUniqueHelperNames) + public Emitter(SourceProductionContext context, SourceGenerationSpec sourceGenSpec) { _context = context; _sourceGenSpec = sourceGenSpec; - - if (emitUniqueHelperNames) - { - GeneratorHelpers.MakeNameUnique(ref _generatedNamespaceName); - } } public void Emit() @@ -51,7 +45,7 @@ public void Emit() EmitInterceptsLocationAttrDecl(); - EmitStartBlock($"namespace {_generatedNamespaceName}"); + EmitStartBlock($"namespace {ProjectName}"); EmitUsingStatements(); _writer.WriteLine(); @@ -260,10 +254,8 @@ private void EmitUsingStatements() private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn) { string returnPostfix = voidReturn ? string.Empty : " null"; - string methodIdentifier = Identifier.HasValueOrChildren; - _writer.WriteLine($$""" - if (!{{methodIdentifier}}({{Identifier.configuration}})) + if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}})) { return{{returnPostfix}}; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 874d2cf9eab60..64db4eb58b1f7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -177,15 +177,14 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || return _createdSpecs[type] = spec; } - private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type) + private void RegisterTypeForBindCoreMainGen(TypeSpec typeSpec) { - if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet? types)) + if (typeSpec.NeedsMemberBinding) { - _sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet(); + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, typeSpec); + RegisterTypeForBindCoreGen(typeSpec); + _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; } - - types.Add(type); - _sourceGenSpec.MethodsToGen_CoreBindingHelper |= method; } private void RegisterTypeForBindCoreGen(TypeSpec typeSpec) @@ -196,16 +195,30 @@ private void RegisterTypeForBindCoreGen(TypeSpec typeSpec) } } - private void RegisterGenMethodAsInterceptor(Enum method, IInvocationOperation operation) + private void RegisterTypeForGetCoreGen(TypeSpec typeSpec) + { + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec); + _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; + } + + private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type) { - if (!_sourceGenSpec.GenMethodsInterceptionInfo.TryGetValue(method, out List? info)) + if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet? types)) { - _sourceGenSpec.GenMethodsInterceptionInfo[method] = info = new List(); + _sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet(); } - info.Add(new InterceptorLocationInfo(operation)); + types.Add(type); + _sourceGenSpec.MethodsToGen_CoreBindingHelper |= method; } + /// + /// Registers interceptors for root binding methods, except for ConfigurationBinder.Bind, + /// which is handled by + /// + private void RegisterAsInterceptor(Enum method, IInvocationOperation operation) => + _sourceGenSpec.InterceptionInfo.RegisterCacheEntry(method, new InterceptorLocationInfo(operation)); + private static bool IsNullable(ITypeSymbol type, [NotNullWhen(true)] out ITypeSymbol? underlyingType) { if (type is INamedTypeSymbol { IsGenericType: true } genericType && @@ -901,4 +914,19 @@ private void RegisterTypeDiagnostic(ITypeSymbol causingType, InvocationDiagnosti } } } + + public static class ParserExtensions + { + public static void RegisterCacheEntry(this Dictionary cache, TKey key, TEntry entry) + where TKey : notnull + where TValue : ICollection, new() + { + if (!cache.TryGetValue(key, out TValue? entryCollection)) + { + cache[key] = entryCollection = new TValue(); + } + + entryCollection.Add(entry); + } + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs index 98af88f143fcc..13158753c3f07 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs @@ -12,17 +12,23 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public sealed partial class ConfigurationBindingGenerator { /// - /// Supresses false-positive diagnostics emitted by the linker analyzers - /// when analyzing binding invocations that we have substituted.Workaround - /// for https://github.com/dotnet/roslyn/issues/68669. + /// Supresses false-positive diagnostics emitted by the linker + /// when analyzing binding invocations that we have intercepted. + /// Workaround for https://github.com/dotnet/roslyn/issues/68669. /// [DiagnosticAnalyzer(LanguageNames.CSharp)] public sealed class Suppressor : DiagnosticSuppressor { private const string Justification = "The target method has been intercepted by a generated static variant."; + /// + /// Suppression descriptor for IL2026: Members attributed with RequiresUnreferencedCode may break when trimming. + /// private static readonly SuppressionDescriptor RUCDiagnostic = new(id: "SYSLIBSUPPRESS0002", suppressedDiagnosticId: "IL2026", Justification); + /// + /// Suppression descriptor for IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as native AOT. + /// private static readonly SuppressionDescriptor RDCDiagnostic = new(id: "SYSLIBSUPPRESS0003", suppressedDiagnosticId: "IL3050", Justification); public override ImmutableArray SupportedSuppressions => ImmutableArray.Create(RUCDiagnostic, RDCDiagnostic); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs index 870a7410344a9..fbca2dd3cfc50 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs @@ -16,8 +16,6 @@ public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerato { private static readonly string ProjectName = Emitter.s_assemblyName.Name; - public bool EmitUniqueHelperNames { get; init; } = true; - public void Initialize(IncrementalGeneratorInitializationContext context) { #if LAUNCH_DEBUGGER @@ -43,7 +41,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc)); } - private void Execute(CompilationData compilationData, ImmutableArray inputCalls, SourceProductionContext context) + private static void Execute(CompilationData compilationData, ImmutableArray inputCalls, SourceProductionContext context) { if (inputCalls.IsDefaultOrEmpty) { @@ -59,7 +57,7 @@ private void Execute(CompilationData compilationData, ImmutableArray= LanguageVersion.Preview; + // We don't have a CSharp21 value available yet. Polyfill the value here for forward compat, rather than use the LangugeVersion.Preview enum value. + // https://github.com/dotnet/roslyn/blob/168689931cb4e3150641ec2fb188a64ce4b3b790/src/Compilers/CSharp/Portable/LanguageVersion.cs#L218-L232 + const int LangVersion_CSharp12 = 1200; + LanguageVersionIsSupported = (int)compilation.LanguageVersion >= LangVersion_CSharp12; + if (LanguageVersionIsSupported) { TypeSymbols = new KnownTypeSymbols(compilation); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs index 6040f0b63c8ca..64064887c7c70 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using SourceGenerators; + namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { public sealed partial class ConfigurationBindingGenerator @@ -45,14 +48,14 @@ private void EmitGetMethods() if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf)) { StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf, documentation); - _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, {Identifier.Type} {Identifier.type}) => " + + _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}) => " + $"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions}: null);"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions)) { StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions, documentation); - _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, {Identifier.Type} {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " + + _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " + $"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions});"); } } @@ -79,25 +82,30 @@ private void EmitGetValueMethods() if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key)) { StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key, documentation); - _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, {Identifier.Type} {Identifier.type}, string {Identifier.key}) => " + + _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}) => " + $"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key});"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue)) { StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue, documentation); - _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, {Identifier.Type} {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " + + _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " + $"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key}) ?? {Identifier.defaultValue};"); } } private void EmitBindMethods_ConfigurationBinder() { + if (!ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind)) + { + return; + } + string objParamExpr = $"object? {Identifier.obj}"; if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance)) { - EmitMethodImplementation( + EmitMethods( MethodsToGen_ConfigurationBinder.Bind_instance, additionalParams: objParamExpr, configExpression: Identifier.configuration, @@ -106,7 +114,7 @@ private void EmitBindMethods_ConfigurationBinder() if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions)) { - EmitMethodImplementation( + EmitMethods( MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions, additionalParams: $"{objParamExpr}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}", configExpression: Identifier.configuration, @@ -115,21 +123,41 @@ private void EmitBindMethods_ConfigurationBinder() if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_key_instance)) { - EmitMethodImplementation( + EmitMethods( MethodsToGen_ConfigurationBinder.Bind_key_instance, additionalParams: $"string {Identifier.key}, {objParamExpr}", - configExpression: $"{Identifier.configuration}?.{Identifier.GetSection}({Identifier.key})", + configExpression: $"{Expression.configurationGetSection}({Identifier.key})", configureOptions: false); } - void EmitMethodImplementation(MethodsToGen_ConfigurationBinder method, string additionalParams, string configExpression, bool configureOptions) + void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParams, string configExpression, bool configureOptions) { - string configureOptionsArg = configureOptions ? Identifier.configureOptions : $"{Identifier.configureOptions}: null"; - string returnExpression = $"{Identifier.BindCoreMain}({configExpression}, {Identifier.obj}, {configureOptionsArg})"; - - StartMethodDefinition(method, "Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively."); - _writer.WriteLine($"public static void {Identifier.Bind}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams}) => " - + $"{returnExpression};"); + foreach (KeyValuePair> pair in _sourceGenSpec.InterceptionInfo_ConfigBinder.GetOverloadInfo(method)) + { + (TypeSpec type, List interceptorInfoList) = (pair.Key, pair.Value); + + EmitBlankLineIfRequired(); + _writer.WriteLine($"/// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively."); + EmitInterceptsLocationAnnotations(interceptorInfoList); + EmitStartBlock($"public static void {Identifier.Bind}_{type.DisplayString.ToIdentifierSubstring()}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})"); + + if (!EmitInitException(type) && type.NeedsMemberBinding) + { + string binderOptionsArg = configureOptions ? $"{Identifier.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null"; + + EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); + if (!type.IsValueType) + { + EmitCheckForNullArgument_WithBlankLine(Identifier.obj); + } + _writer.WriteLine($$""" + var {{Identifier.typedObj}} = ({{type.EffectiveType.DisplayString}}){{Identifier.obj}}; + {{nameof(MethodsToGen_CoreBindingHelper.BindCore)}}({{configExpression}}, ref {{Identifier.typedObj}}, {{binderOptionsArg}}); + """); + } + + EmitEndBlock(); + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs index db3f6660561a9..f30408fad596d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -18,7 +19,6 @@ private sealed partial class Emitter private void EmitCoreBindingHelpers() { Debug.Assert(_emitBlankLineBeforeNextStatement); - EmitBindingExtStartRegion("Core binding"); EmitConfigurationKeyCaches(); EmitGetCoreMethod(); @@ -73,12 +73,14 @@ private void EmitGetCoreMethod() EmitIConfigurationHasValueOrChildrenCheck(voidReturn: false); + bool isFirstType = true; foreach (TypeSpec type in types) { TypeSpec effectiveType = type.EffectiveType; TypeSpecKind kind = effectiveType.SpecKind; + string conditionKindExpr = GetConditionKindExpr(ref isFirstType); - EmitStartBlock($"if (type == typeof({type.DisplayString}))"); + EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); if (effectiveType is ParsableFromStringSpec stringParsableType) { @@ -104,10 +106,10 @@ private void EmitGetCoreMethod() } EmitEndBlock(); - _writer.WriteLine(); } - Emit_NotSupportedException_TypeNotDetectedAsInput("'{type}'"); + _writer.WriteLine(); + Emit_NotSupportedException_TypeNotDetectedAsInput(); EmitEndBlock(); _emitBlankLineBeforeNextStatement = true; } @@ -135,9 +137,11 @@ private void EmitGetValueCoreMethod() _writer.WriteLine(); + bool isFirstType = true; foreach (TypeSpec type in targetTypes) { - EmitStartBlock($"if ({Identifier.type} == typeof({type.DisplayString}))"); + string conditionKindExpr = GetConditionKindExpr(ref isFirstType); + EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); EmitBindLogicFromString( (ParsableFromStringSpec)type.EffectiveType, @@ -148,9 +152,9 @@ private void EmitGetValueCoreMethod() useIncrementalStringValueIdentifier: false); EmitEndBlock(); - _writer.WriteLine(); } + _writer.WriteLine(); _writer.WriteLine("return null;"); EmitEndBlock(); _emitBlankLineBeforeNextStatement = true; @@ -158,53 +162,38 @@ private void EmitGetValueCoreMethod() private void EmitBindCoreMainMethod() { - if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCore, out HashSet? targetTypes)) + if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCoreMain, out HashSet? targetTypes)) { return; } EmitBlankLineIfRequired(); - - EmitStartBlock($"public static void {Identifier.BindCoreMain}({Identifier.IConfiguration}? {Identifier.configuration}, object? {Identifier.obj}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})"); - + EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}({Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})"); EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); EmitCheckForNullArgument_WithBlankLine(Identifier.obj); - + EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true); _writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});"); _writer.WriteLine(); - EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true); - + bool isFirstType = true; foreach (TypeSpec type in targetTypes) { - string typedObjIdentifier = GetIncrementalIdentifier(Identifier.typedObj); - EmitStartBlock($"if ({Identifier.obj} is {type.DisplayString} {typedObjIdentifier})"); - TypeSpec effectiveType = type.EffectiveType; + string conditionKindExpr = GetConditionKindExpr(ref isFirstType); + + EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); if (!EmitInitException(effectiveType)) { - string objIdentifier; - if (type == effectiveType) - { - objIdentifier = typedObjIdentifier; - } - else - { - objIdentifier = Identifier.temp; - _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){typedObjIdentifier};"); - } - - EmitBindCoreCall(type, objIdentifier, Identifier.configuration, InitializationKind.None); + _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.obj};"); + EmitBindCoreCall(type, Identifier.temp, Identifier.configuration, InitializationKind.None); _writer.WriteLine($"return;"); } - EmitEndBlock(); - _writer.WriteLine(); } - Emit_NotSupportedException_TypeNotDetectedAsInput("'{obj.GetType()}'"); + _writer.WriteLine(); + Emit_NotSupportedException_TypeNotDetectedAsInput(); EmitEndBlock(); - _emitBlankLineBeforeNextStatement = true; } private void EmitBindCoreMethods() @@ -229,11 +218,6 @@ private void EmitBindCoreMethod(TypeSpec type) string objParameterExpression = $"ref {type.DisplayString} {Identifier.obj}"; EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})"); - if (!type.IsValueType) - { - EmitCheckForNullArgument_WithBlankLine(Identifier.obj); - } - TypeSpec effectiveType = type.EffectiveType; if (effectiveType is EnumerableSpec enumerable) { @@ -396,30 +380,37 @@ void EmitThrowBlock(string condition) => """); } } + private void EmitHelperMethods() { - if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore | MethodsToGen_CoreBindingHelper.GetCore)) + // Emitted if we are to bind objects with complex members, or if we're emitting BindCoreMain or GetCore methods. + bool emitAsConfigWithChildren = ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren); + + if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore)) { + EmitBlankLineIfRequired(); EmitValidateConfigurationKeysMethod(); - _writer.WriteLine(); + } + + if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore)) + { + // HasValueOrChildren references this method. + Debug.Assert(emitAsConfigWithChildren); + EmitBlankLineIfRequired(); EmitHasValueOrChildrenMethod(); - _writer.WriteLine(); - EmitAsConfigWithChildrenMethod(); - _emitBlankLineBeforeNextStatement = true; } - else if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren)) + + if (emitAsConfigWithChildren) { - _writer.WriteLine(); + EmitBlankLineIfRequired(); EmitAsConfigWithChildrenMethod(); - _emitBlankLineBeforeNextStatement = true; } - if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore | MethodsToGen_CoreBindingHelper.GetCore) || + if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore) || ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions)) { - _writer.WriteLine(); + EmitBlankLineIfRequired(); EmitGetBinderOptionsHelper(); - _emitBlankLineBeforeNextStatement = true; } bool enumTypeExists = false; @@ -483,7 +474,7 @@ private void EmitHasValueOrChildrenMethod() { return true; } - return {{Identifier.AsConfigWithChildren}}({{Identifier.configuration}}) is not null; + return {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.configuration}}) is not null; } """); } @@ -491,7 +482,7 @@ private void EmitHasValueOrChildrenMethod() private void EmitAsConfigWithChildrenMethod() { _writer.WriteLine($$""" - public static {{Identifier.IConfiguration}}? {{Identifier.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) + public static {{Identifier.IConfiguration}}? {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) { foreach ({{Identifier.IConfigurationSection}} _ in {{Identifier.configuration}}.{{Identifier.GetChildren}}()) { @@ -807,7 +798,7 @@ private bool EmitBindImplForMember( return true; } - string sectionValidationCall = $"{Identifier.AsConfigWithChildren}({sectionParseExpr})"; + string sectionValidationCall = $"{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}({sectionParseExpr})"; string sectionIdentifier = GetIncrementalIdentifier(Identifier.section); EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})"); @@ -911,6 +902,9 @@ private void EmitCollectionCastIfRequired(CollectionSpec type, out string objIde private void Emit_Foreach_Section_In_ConfigChildren_StartBlock() => EmitStartBlock($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())"); + private void Emit_NotSupportedException_TypeNotDetectedAsInput() => + _writer.WriteLine(@$"throw new NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, "{type}")}"");"); + private static string GetSectionPathFromConfigurationExpression(string configurationKeyName) => $@"{GetSectionFromConfigurationExpression(configurationKeyName)}.{Identifier.Path}"; @@ -920,11 +914,19 @@ private static string GetSectionFromConfigurationExpression(string configuration return $@"{Identifier.configuration}.{Identifier.GetSection}({argExpr})"; } - private static string GetConfigKeyCacheFieldName(ObjectSpec type) => - $"s_configKeys_{type.DisplayStringWithoutSpecialCharacters}"; + private static string GetConditionKindExpr(ref bool isFirstType) + { + if (isFirstType) + { + isFirstType = false; + return "if"; + } - private void Emit_NotSupportedException_TypeNotDetectedAsInput(string typeArgExpr) => - _writer.WriteLine(@$"throw new NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, typeArgExpr)}"");"); + return "else if"; + } + + private static string GetConfigKeyCacheFieldName(ObjectSpec type) => + $"s_configKeys_{type.DisplayString.ToIdentifierSubstring()}"; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index ab214fc739436..bad56b7ce3275 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -71,9 +71,7 @@ private static class Identifier public const string AddSingleton = nameof(AddSingleton); public const string Any = nameof(Any); public const string Array = nameof(Array); - public const string AsConfigWithChildren = nameof(AsConfigWithChildren); public const string Bind = nameof(Bind); - public const string BindCoreMain = nameof(BindCoreMain); public const string BinderOptions = nameof(BinderOptions); public const string BindingExtensions = nameof(BindingExtensions); public const string ConfigurationChangeTokenSource = nameof(ConfigurationChangeTokenSource); @@ -111,7 +109,6 @@ private static class Identifier public const string TOptions = nameof(TOptions); public const string TryCreate = nameof(TryCreate); public const string TryGetValue = nameof(TryGetValue); - public const string TryParse = nameof(TryParse); public const string Type = nameof(Type); public const string Uri = nameof(Uri); public const string ValidateConfigurationKeys = nameof(ValidateConfigurationKeys); @@ -128,17 +125,22 @@ private void EmitInterceptsLocationAnnotations(Enum generatedBindingOverload) // The only time a generated binding method won't have any locations to // intercept is when either of these methods are used as helpers for // other generated OptionsBuilder or ServiceCollection binding extensions. - bool interceptsCalls = _sourceGenSpec.GenMethodsInterceptionInfo.TryGetValue(generatedBindingOverload, out List? infoList); + bool interceptsCalls = _sourceGenSpec.InterceptionInfo.TryGetValue(generatedBindingOverload, out List? infoList); Debug.Assert(interceptsCalls || generatedBindingOverload is MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions || generatedBindingOverload is MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions); if (interceptsCalls) { - foreach (InterceptorLocationInfo info in infoList) - { - _writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]"); - } + EmitInterceptsLocationAnnotations(infoList); + } + } + + private void EmitInterceptsLocationAnnotations(List infoList) + { + foreach (InterceptorLocationInfo info in infoList) + { + _writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]"); } } @@ -237,7 +239,18 @@ private bool EmitInitException(TypeSpec type) private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}"; private static string GetInitalizeMethodDisplayString(ObjectSpec type) => - $"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayStringWithoutSpecialCharacters}"; + $"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayString.ToIdentifierSubstring()}"; } } + + internal static class EmitterExtensions + { + public static string ToIdentifierSubstring(this string typeDisplayName) => + typeDisplayName + .Replace("[]", nameof(Array)) + .Replace(", ", string.Empty) + .Replace(".", string.Empty) + .Replace("<", string.Empty) + .Replace(">", string.Empty); + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs index 91f7fdd43478d..d49198196fd49 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs @@ -71,10 +71,11 @@ private void EmitBindConfigurationMethod() EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath); EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>"); - + EmitCheckForNullArgument_WithBlankLine(Identifier.obj); + EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); _writer.WriteLine($$""" {{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}}); - {{Identifier.BindCoreMain}}({{Identifier.section}}, {{Identifier.obj}}, {{Identifier.configureOptions}}); + {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}); """); EmitEndBlock(endBraceTrailingSource: ");"); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs index 804159ccb4bf8..0348eb5047e97 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs @@ -62,7 +62,7 @@ private void EmitConfigureMethods() _writer.WriteLine($$""" OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}}); {{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}})); - return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{Identifier.BindCoreMain}}({{Identifier.configuration}}, {{Identifier.obj}}, {{Identifier.configureOptions}}))); + return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}){{Identifier.configureOptions}}))); """); EmitEndBlock(); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs index d355e071904a3..d1dc4f4afa7e7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections; +using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Operations; @@ -8,7 +11,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal readonly record struct InterceptorLocationInfo + internal sealed record InterceptorLocationInfo { public InterceptorLocationInfo(IInvocationOperation operation) { @@ -35,4 +38,53 @@ public InterceptorLocationInfo(IInvocationOperation operation) private static string GetInterceptorFilePath(SyntaxTree tree, SourceReferenceResolver? resolver) => resolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath; } + + internal sealed record ConfigurationBinderInterceptorInfo + { + private OverloadInterceptorInfo? _bind_Instance; + private OverloadInterceptorInfo? _bind_instance_BinderOptions; + private OverloadInterceptorInfo? _bind_key_instance; + + public void RegisterOverloadInfo(MethodsToGen_ConfigurationBinder overload, TypeSpec type, IInvocationOperation operation) + { + OverloadInterceptorInfo overloadInfo = DetermineOverload(overload, initIfNull: true); + overloadInfo.RegisterLocationInfo(type, operation); + } + + public OverloadInterceptorInfo GetOverloadInfo(MethodsToGen_ConfigurationBinder overload) => + DetermineOverload(overload, initIfNull: false) ?? throw new ArgumentNullException(nameof(overload)); + + private OverloadInterceptorInfo? DetermineOverload(MethodsToGen_ConfigurationBinder overload, bool initIfNull) + { + return overload switch + { + MethodsToGen_ConfigurationBinder.Bind_instance => InitIfNull(ref _bind_Instance), + MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions => InitIfNull(ref _bind_instance_BinderOptions), + MethodsToGen_ConfigurationBinder.Bind_key_instance => InitIfNull(ref _bind_key_instance), + _ => throw new InvalidOperationException(nameof(overload)), + }; + + OverloadInterceptorInfo InitIfNull(ref OverloadInterceptorInfo? info) + { + if (initIfNull) + { + info ??= new OverloadInterceptorInfo(); + } + + return info; + } + } + } + + internal sealed record OverloadInterceptorInfo : IEnumerable>> + { + private readonly Dictionary> _typeInterceptionInfo = new(); + + public void RegisterLocationInfo(TypeSpec type, IInvocationOperation operation) => + _typeInterceptionInfo.RegisterCacheEntry(type, new InterceptorLocationInfo(operation)); + + public IEnumerator>> GetEnumerator() => _typeInterceptionInfo.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs index d0ba0699b2aba..2c582b20e8ebd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs @@ -12,8 +12,10 @@ public enum MethodsToGen_CoreBindingHelper BindCore = 0x1, GetCore = 0x2, GetValueCore = 0x4, - Initialize = 0x8, - AsConfigWithChildren = 0x10, + BindCoreMain = 0x8, + Initialize = 0x10, + HasValueOrChildren = 0x20, + AsConfigWithChildren = 0x40, } /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs index 5ff93853676a6..e24ce11fe4374 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs @@ -100,9 +100,9 @@ private void RegisterBindInvocation(BinderInvocation invocation) return; } - if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is not null) + if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) { - RegisterAsInterceptor(overload, invocation.Operation); + RegisterAsInterceptor_ConfigBinder_BindMethod(overload, typeSpec, invocation.Operation); } static ITypeSymbol? ResolveType(IOperation conversionOperation) => @@ -176,8 +176,8 @@ private void RegisterGetInvocation(BinderInvocation invocation) if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec) { - RegisterAsInterceptor(overload, invocation.Operation); - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec); + RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation); + RegisterTypeForGetCoreGen(typeSpec); } } @@ -245,15 +245,26 @@ private void RegisterGetValueInvocation(BinderInvocation invocation) if (IsParsableFromString(effectiveType, out _) && GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) { - RegisterAsInterceptor(overload, invocation.Operation); + RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation); RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec); } } - private void RegisterAsInterceptor(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation) + private void RegisterAsInterceptor_ConfigBinder(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation) { _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; - RegisterGenMethodAsInterceptor(overload, operation); + RegisterAsInterceptor(overload, operation); + } + + /// + /// Registers generated Bind methods as interceptors. This is done differently from other root + /// methods because we need to + /// explicitly account for the type to bind, to avoid type-check issues for polymorphic objects. + /// + private void RegisterAsInterceptor_ConfigBinder_BindMethod(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation) + { + _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; + _sourceGenSpec.InterceptionInfo_ConfigBinder.RegisterOverloadInfo(overload, typeSpec, operation); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs index eb7407a0a571e..a62e63c0d90d5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs @@ -68,7 +68,7 @@ 3 when SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, if (overload is not MethodsToGen_Extensions_OptionsBuilder.None) { - RegisterAsInterceptor(overload, operation); + RegisterAsInterceptor_OptionsBuilder(overload, operation); RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec); } } @@ -85,15 +85,15 @@ private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeS @params[1].Type.SpecialType is SpecialType.System_String && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type)) { - RegisterAsInterceptor(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation); - RegisterTypeForBindCoreGen(typeSpec); + RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation); + RegisterTypeForBindCoreMainGen(typeSpec); } } - private void RegisterAsInterceptor(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation) + private void RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation) { _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= overload; - RegisterGenMethodAsInterceptor(overload, operation); + RegisterAsInterceptor(overload, operation); // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource. _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs index d4b1bb30f1b1a..c356b29a69eff 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs @@ -79,14 +79,14 @@ @params[1].Type.SpecialType is SpecialType.System_String && } RegisterTypeForMethodGen(overload, typeSpec); - RegisterGenMethodAsInterceptor(overload, operation); + RegisterAsInterceptor(overload, operation); } private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec) { _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload; _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); - RegisterTypeForBindCoreGen(typeSpec); + RegisterTypeForBindCoreMainGen(typeSpec); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj index 3ad3c09f9c2fd..e895d18c5556c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj @@ -22,7 +22,6 @@ - diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs index c8911850badb6..8cc0ba68b4938 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs @@ -22,10 +22,6 @@ public ObjectSpec(INamedTypeSymbol type) : base(type) { } public List ConstructorParameters { get; } = new(); - private string _displayStringWithoutSpecialCharacters; - public string DisplayStringWithoutSpecialCharacters => - _displayStringWithoutSpecialCharacters ??= $"{DisplayString.Replace(".", string.Empty).Replace("<", string.Empty).Replace(">", string.Empty)}"; - public override bool NeedsMemberBinding => CanInitialize && Properties.Values.Count > 0 && Properties.Values.Any(p => p.ShouldBind()); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs index cf37acd6f39db..760d57b1dcc88 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs @@ -8,7 +8,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { internal sealed record SourceGenerationSpec { - public Dictionary> GenMethodsInterceptionInfo { get; } = new(); + public Dictionary> InterceptionInfo { get; } = new(); + public ConfigurationBinderInterceptorInfo InterceptionInfo_ConfigBinder { get; } = new(); + public Dictionary> TypesForGen_CoreBindingHelper_Methods { get; } = new(); public HashSet PrimitivesForHelperGen { get; } = new(); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx index 301913987d7c7..3978cbaac6ce4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx @@ -133,10 +133,10 @@ The collection element type is not supported: '{0}'. - The project's language version has to be at least 'C# 11'. + The project's language version has to be at least 'C# 12'. - Language version is required to be at least C# 11 + Language version is required to be at least C# 12 Cannot create instance of type '{0}' because it is missing a public instance constructor. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf index e248c54626865..c6672eaff0bcd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Jazyková verze projektu musí být alespoň C# 11 + The project's language version has to be at least 'C# 12'. + Jazyková verze projektu musí být alespoň C# 11 - Language version is required to be at least C# 11 - Verze jazyka musí být alespoň C# 11 + Language version is required to be at least C# 12 + Verze jazyka musí být alespoň C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf index 1fa847592bd02..5f353065a5f51 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Die Sprachversion des Projekts muss mindestens „C# 11“ sein + The project's language version has to be at least 'C# 12'. + Die Sprachversion des Projekts muss mindestens „C# 11“ sein - Language version is required to be at least C# 11 - Die Sprachversion muss mindestens C# 11 sein + Language version is required to be at least C# 12 + Die Sprachversion muss mindestens C# 11 sein diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf index c52b2317ceade..cd54149e66c2f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - La versión del lenguaje del proyecto debe ser al menos "C# 11". + The project's language version has to be at least 'C# 12'. + La versión del lenguaje del proyecto debe ser al menos "C# 11". - Language version is required to be at least C# 11 - La versión del lenguaje debe ser al menos C# 11 + Language version is required to be at least C# 12 + La versión del lenguaje debe ser al menos C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf index 19362d7336208..b1c0753a49e8a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - La version de langage du projet doit être au moins « C# 11 ». + The project's language version has to be at least 'C# 12'. + La version de langage du projet doit être au moins « C# 11 ». - Language version is required to be at least C# 11 - La version du langage doit être au moins C# 11 + Language version is required to be at least C# 12 + La version du langage doit être au moins C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf index f418a83d0d422..27d10a7ee5f9f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - La versione del linguaggio del progetto deve essere almeno 'C# 11'. + The project's language version has to be at least 'C# 12'. + La versione del linguaggio del progetto deve essere almeno 'C# 11'. - Language version is required to be at least C# 11 - La versione del linguaggio deve essere almeno C# 11 + Language version is required to be at least C# 12 + La versione del linguaggio deve essere almeno C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf index ba59cfba40a89..24621bcc8b3d2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。 + The project's language version has to be at least 'C# 12'. + プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。 - Language version is required to be at least C# 11 - 言語バージョンは少なくとも C# 11 である必要があります + Language version is required to be at least C# 12 + 言語バージョンは少なくとも C# 11 である必要があります diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf index 10b9b107c4aad..217a0cd9f8e54 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - 프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다. + The project's language version has to be at least 'C# 12'. + 프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다. - Language version is required to be at least C# 11 - 언어 버전은 C# 11 이상이어야 합니다. + Language version is required to be at least C# 12 + 언어 버전은 C# 11 이상이어야 합니다. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf index 2b558c588ebfb..0b24813a77a80 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Wersja językowa projektu musi mieć wartość co najmniej „C# 11”. + The project's language version has to be at least 'C# 12'. + Wersja językowa projektu musi mieć wartość co najmniej „C# 11”. - Language version is required to be at least C# 11 - Wymagana jest wersja językowa co najmniej C# 11 + Language version is required to be at least C# 12 + Wymagana jest wersja językowa co najmniej C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf index 9d2a51c6aa9c9..0ad700e64e9eb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - A versão do idioma do projeto deve ser no mínimo 'C# 11'. + The project's language version has to be at least 'C# 12'. + A versão do idioma do projeto deve ser no mínimo 'C# 11'. - Language version is required to be at least C# 11 - A versão do idioma deve ser pelo menos C# 11 + Language version is required to be at least C# 12 + A versão do idioma deve ser pelo menos C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf index 1ed03c55891a9..5e53330060c30 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Версия языка проекта должна быть не ниже "C# 11". + The project's language version has to be at least 'C# 12'. + Версия языка проекта должна быть не ниже "C# 11". - Language version is required to be at least C# 11 - Версия языка должна быть не ниже C# 11 + Language version is required to be at least C# 12 + Версия языка должна быть не ниже C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf index 8a6dbf76bab7f..cfaea488fd195 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Projenin dil sürümü en az 'C# 11' olmalıdır. + The project's language version has to be at least 'C# 12'. + Projenin dil sürümü en az 'C# 11' olmalıdır. - Language version is required to be at least C# 11 - Dil sürümünün en az C# 11 olması gerekir + Language version is required to be at least C# 12 + Dil sürümünün en az C# 11 olması gerekir diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf index 9d0c0eb3a5d6d..3dfb711b39b4e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - 项目的语言版本必须至少为 "C# 11"。 + The project's language version has to be at least 'C# 12'. + 项目的语言版本必须至少为 "C# 11"。 - Language version is required to be at least C# 11 - 语言版本必须至少为 C# 11 + Language version is required to be at least C# 12 + 语言版本必须至少为 C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf index dc6ded618c8e9..9917b18949880 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - 專案的語言版本必須至少為 'C# 11'。 + The project's language version has to be at least 'C# 12'. + 專案的語言版本必須至少為 'C# 11'。 - Language version is required to be at least C# 11 - 語言版本要求至少為 C#11 + Language version is required to be at least C# 12 + 語言版本要求至少為 C#11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index 4f16767be2f50..ccf936978c792 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -4,11 +4,9 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; -using System.Text; #if BUILDING_SOURCE_GENERATOR_TESTS using Microsoft.Extensions.Configuration; #endif @@ -2037,6 +2035,7 @@ public void ComplexObj_As_Enumerable_Element() ValidateGeolocation(obj); } +#if !BUILDING_SOURCE_GENERATOR_TESTS [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] public void TraceSwitchTest() { @@ -2048,7 +2047,6 @@ public void TraceSwitchTest() configurationBuilder.AddInMemoryCollection(dic); var config = configurationBuilder.Build(); -#if !BUILDING_SOURCE_GENERATOR_TESTS TraceSwitch ts = new(displayName: "TraceSwitch", description: "This switch is set via config."); ConfigurationBinder.Bind(config, "TraceSwitch", ts); Assert.Equal(TraceLevel.Info, ts.Level); @@ -2056,8 +2054,8 @@ public void TraceSwitchTest() // Value property is not publicly exposed in .NET Framework. Assert.Equal("Info", ts.Value); #endif // NETCOREAPP -#endif // !BUILDING_SOURCE_GENERATOR_TESTS } +#endif private void ValidateGeolocation(IGeolocation location) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt index 52d0cd6a593ab..528847cfeb3a3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt @@ -60,92 +60,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new NotSupportedException($"Unable to bind to type ''{type}'': generator did not detect the type as input."); - } - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) - { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is Program.CustomDictionary typedObj1) - { - BindCore(configuration, ref typedObj1, binderOptions); - return; - } - - if (obj is Program.CustomList typedObj3) - { - BindCore(configuration, ref typedObj3, binderOptions); - return; - } - - if (obj is List typedObj5) - { - BindCore(configuration, ref typedObj5, binderOptions); - return; - } - - if (obj is ICollection typedObj7) - { - BindCore(configuration, ref typedObj7, binderOptions); - return; - } - - if (obj is IReadOnlyList typedObj9) - { - BindCore(configuration, ref typedObj9, binderOptions); - return; - } - - if (obj is Dictionary typedObj11) - { - BindCore(configuration, ref typedObj11, binderOptions); - return; - } - - if (obj is IDictionary typedObj13) - { - BindCore(configuration, ref typedObj13, binderOptions); - return; - } - - if (obj is IReadOnlyDictionary typedObj15) - { - BindCore(configuration, ref typedObj15, binderOptions); - return; - } - - if (obj is Program.MyClassWithCustomCollections typedObj17) - { - BindCore(configuration, ref typedObj17, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -157,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.CustomList obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -173,11 +87,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -189,11 +98,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref ICollection obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -205,11 +109,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IReadOnlyList obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - if (obj is not ICollection temp) { return; @@ -226,11 +125,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -242,11 +136,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -258,11 +147,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - if (obj is not IDictionary temp) { return; @@ -279,46 +163,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions); - if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section19) + if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1) { - Program.CustomDictionary? temp21 = obj.CustomDictionary; - temp21 ??= new Program.CustomDictionary(); - BindCore(section19, ref temp21, binderOptions); - obj.CustomDictionary = temp21; + Program.CustomDictionary? temp3 = obj.CustomDictionary; + temp3 ??= new Program.CustomDictionary(); + BindCore(section1, ref temp3, binderOptions); + obj.CustomDictionary = temp3; } - if (AsConfigWithChildren(configuration.GetSection("CustomList")) is IConfigurationSection section22) + if (AsConfigWithChildren(configuration.GetSection("CustomList")) is IConfigurationSection section4) { - Program.CustomList? temp24 = obj.CustomList; - temp24 ??= new Program.CustomList(); - BindCore(section22, ref temp24, binderOptions); - obj.CustomList = temp24; + Program.CustomList? temp6 = obj.CustomList; + temp6 ??= new Program.CustomList(); + BindCore(section4, ref temp6, binderOptions); + obj.CustomList = temp6; } - if (AsConfigWithChildren(configuration.GetSection("IReadOnlyList")) is IConfigurationSection section25) + if (AsConfigWithChildren(configuration.GetSection("IReadOnlyList")) is IConfigurationSection section7) { - IReadOnlyList? temp27 = obj.IReadOnlyList; - temp27 = temp27 is null ? new List() : new List(temp27); - BindCore(section25, ref temp27, binderOptions); - obj.IReadOnlyList = temp27; + IReadOnlyList? temp9 = obj.IReadOnlyList; + temp9 = temp9 is null ? new List() : new List(temp9); + BindCore(section7, ref temp9, binderOptions); + obj.IReadOnlyList = temp9; } - if (AsConfigWithChildren(configuration.GetSection("IReadOnlyDictionary")) is IConfigurationSection section28) + if (AsConfigWithChildren(configuration.GetSection("IReadOnlyDictionary")) is IConfigurationSection section10) { - IReadOnlyDictionary? temp30 = obj.IReadOnlyDictionary; - temp30 = temp30 is null ? new Dictionary() : temp30.ToDictionary(pair => pair.Key, pair => pair.Value); - BindCore(section28, ref temp30, binderOptions); - obj.IReadOnlyDictionary = temp30; + IReadOnlyDictionary? temp12 = obj.IReadOnlyDictionary; + temp12 = temp12 is null ? new Dictionary() : temp12.ToDictionary(pair => pair.Key, pair => pair.Value); + BindCore(section10, ref temp12, binderOptions); + obj.IReadOnlyDictionary = temp12; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt index 35187f8c8d65b..36ac12fd31f83 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt @@ -32,21 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] - public static void Bind(this IConfiguration configuration, object? obj) => BindCoreMain(configuration, obj, configureOptions: null); - - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] - public static void Bind(this IConfiguration configuration, object? obj, Action? configureOptions) => BindCoreMain(configuration, obj, configureOptions); - - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] - public static void Bind(this IConfiguration configuration, string key, object? obj) => BindCoreMain(configuration?.GetSection(key), obj, configureOptions: null); - #endregion IConfiguration extensions. - - #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { if (configuration is null) { @@ -58,47 +44,52 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); + } - if (!HasValueOrChildren(configuration)) + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) + { + if (configuration is null) { - return; + throw new ArgumentNullException(nameof(configuration)); } - if (obj is List typedObj0) + if (obj is null) { - BindCore(configuration, ref typedObj0, binderOptions); - return; + throw new ArgumentNullException(nameof(obj)); } - if (obj is Dictionary typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); + } - if (obj is Dictionary typedObj4) + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) + { + if (configuration is null) { - BindCore(configuration, ref typedObj4, binderOptions); - return; + throw new ArgumentNullException(nameof(configuration)); } - if (obj is Program.MyClass typedObj6) + if (obj is null) { - BindCore(configuration, ref typedObj6, binderOptions); - return; + throw new ArgumentNullException(nameof(obj)); } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + var typedObj = (Program.MyClass)obj; + BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -110,11 +101,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -126,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -143,45 +124,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value9) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value9, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section10) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp12 = obj.MyList; - temp12 ??= new List(); - BindCore(section10, ref temp12, binderOptions); - obj.MyList = temp12; + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section13) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp15 = obj.MyDictionary; - temp15 ??= new Dictionary(); - BindCore(section13, ref temp15, binderOptions); - obj.MyDictionary = temp15; + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section16) + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp18 = obj.MyComplexDictionary; - temp18 ??= new Dictionary(); - BindCore(section16, ref temp18, binderOptions); - obj.MyComplexDictionary = temp18; + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -204,15 +181,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static bool HasValueOrChildren(IConfiguration configuration) - { - if ((configuration as IConfigurationSection)?.Value is not null) - { - return true; - } - return AsConfigWithChildren(configuration) is not null; - } - public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) { foreach (IConfigurationSection _ in configuration.GetChildren()) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt index e1946bd7caddd..02fb06957bb3d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt @@ -32,13 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind(this IConfiguration configuration, object? obj) => BindCoreMain(configuration, obj, configureOptions: null); - #endregion IConfiguration extensions. - - #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { if (configuration is null) { @@ -50,47 +44,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - if (obj is Dictionary typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is Dictionary typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Program.MyClass typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -102,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -118,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -135,45 +88,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value9) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value9, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section10) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp12 = obj.MyList; - temp12 ??= new List(); - BindCore(section10, ref temp12, binderOptions); - obj.MyList = temp12; + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section13) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp15 = obj.MyDictionary; - temp15 ??= new Dictionary(); - BindCore(section13, ref temp15, binderOptions); - obj.MyDictionary = temp15; + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section16) + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp18 = obj.MyComplexDictionary; - temp18 ??= new Dictionary(); - BindCore(section16, ref temp18, binderOptions); - obj.MyComplexDictionary = temp18; + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -196,15 +145,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static bool HasValueOrChildren(IConfiguration configuration) - { - if ((configuration as IConfigurationSection)?.Value is not null) - { - return true; - } - return AsConfigWithChildren(configuration) is not null; - } - public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) { foreach (IConfigurationSection _ in configuration.GetChildren()) @@ -214,24 +154,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return null; } - public static BinderOptions? GetBinderOptions(Action? configureOptions) - { - if (configureOptions is null) - { - return null; - } - - BinderOptions binderOptions = new(); - configureOptions(binderOptions); - - if (binderOptions.BindNonPublicProperties) - { - throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); - } - - return binderOptions; - } - public static int ParseInt(string value, Func getPath) { try diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index 9d099198acdc0..4703980996b88 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -32,13 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind(this IConfiguration configuration, object? obj, Action? configureOptions) => BindCoreMain(configuration, obj, configureOptions); - #endregion IConfiguration extensions. - - #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) { if (configuration is null) { @@ -50,47 +44,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - if (obj is Dictionary typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is Dictionary typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Program.MyClass typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -102,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -118,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -135,45 +88,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value9) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value9, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section10) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp12 = obj.MyList; - temp12 ??= new List(); - BindCore(section10, ref temp12, binderOptions); - obj.MyList = temp12; + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section13) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp15 = obj.MyDictionary; - temp15 ??= new Dictionary(); - BindCore(section13, ref temp15, binderOptions); - obj.MyDictionary = temp15; + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section16) + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp18 = obj.MyComplexDictionary; - temp18 ??= new Dictionary(); - BindCore(section16, ref temp18, binderOptions); - obj.MyComplexDictionary = temp18; + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -196,15 +145,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static bool HasValueOrChildren(IConfiguration configuration) - { - if ((configuration as IConfigurationSection)?.Value is not null) - { - return true; - } - return AsConfigWithChildren(configuration) is not null; - } - public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) { foreach (IConfigurationSection _ in configuration.GetChildren()) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt index 74af70d28e767..9937129699716 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -32,13 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind(this IConfiguration configuration, string key, object? obj) => BindCoreMain(configuration?.GetSection(key), obj, configureOptions: null); - #endregion IConfiguration extensions. - - #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { if (configuration is null) { @@ -50,47 +44,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - if (obj is Dictionary typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is Dictionary typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Program.MyClass typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + var typedObj = (Program.MyClass)obj; + BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -102,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -118,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -135,45 +88,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value9) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value9, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section10) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp12 = obj.MyList; - temp12 ??= new List(); - BindCore(section10, ref temp12, binderOptions); - obj.MyList = temp12; + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section13) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp15 = obj.MyDictionary; - temp15 ??= new Dictionary(); - BindCore(section13, ref temp15, binderOptions); - obj.MyDictionary = temp15; + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section16) + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp18 = obj.MyComplexDictionary; - temp18 ??= new Dictionary(); - BindCore(section16, ref temp18, binderOptions); - obj.MyComplexDictionary = temp18; + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -196,15 +145,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static bool HasValueOrChildren(IConfiguration configuration) - { - if ((configuration as IConfigurationSection)?.Value is not null) - { - return true; - } - return AsConfigWithChildren(configuration) is not null; - } - public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) { foreach (IConfigurationSection _ in configuration.GetChildren()) @@ -214,24 +154,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return null; } - public static BinderOptions? GetBinderOptions(Action? configureOptions) - { - if (configureOptions is null) - { - return null; - } - - BinderOptions binderOptions = new(); - configureOptions(binderOptions); - - if (binderOptions.BindNonPublicProperties) - { - throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); - } - - return binderOptions; - } - public static int ParseInt(string value, Func getPath) { try diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt index 5b512b6414f94..3e6ce1459b289 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt @@ -71,76 +71,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration BindCore(configuration, ref obj, binderOptions); return obj; } - - if (type == typeof(Program.MyClass2)) + else if (type == typeof(Program.MyClass2)) { var obj = new Program.MyClass2(); BindCore(configuration, ref obj, binderOptions); return obj; } - throw new NotSupportedException($"Unable to bind to type ''{type}'': generator did not detect the type as input."); - } - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) - { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is List typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is int[] typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Dictionary typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } - - if (obj is Program.MyClass typedObj8) - { - BindCore(configuration, ref typedObj8, binderOptions); - return; - } - - if (obj is Program.MyClass2 typedObj10) - { - BindCore(configuration, ref typedObj10, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -152,25 +94,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - var temp12 = new List(); - BindCore(configuration, ref temp12, binderOptions); + var temp2 = new List(); + BindCore(configuration, ref temp2, binderOptions); int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp12.Count); - temp12.CopyTo(obj, originalCount); + Array.Resize(ref obj, originalCount + temp2.Count); + temp2.CopyTo(obj, originalCount); } public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -182,60 +114,51 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value15) + if (configuration["MyInt"] is string value5) { - obj.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section16) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) { - List? temp18 = obj.MyList; - temp18 ??= new List(); - BindCore(section16, ref temp18, binderOptions); - obj.MyList = temp18; + List? temp8 = obj.MyList; + temp8 ??= new List(); + BindCore(section6, ref temp8, binderOptions); + obj.MyList = temp8; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section19) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section9) { - int[]? temp21 = obj.MyArray; - temp21 ??= new int[0]; - BindCore(section19, ref temp21, binderOptions); - obj.MyArray = temp21; + int[]? temp11 = obj.MyArray; + temp11 ??= new int[0]; + BindCore(section9, ref temp11, binderOptions); + obj.MyArray = temp11; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section22) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section12) { - Dictionary? temp24 = obj.MyDictionary; - temp24 ??= new Dictionary(); - BindCore(section22, ref temp24, binderOptions); - obj.MyDictionary = temp24; + Dictionary? temp14 = obj.MyDictionary; + temp14 ??= new Dictionary(); + BindCore(section12, ref temp14, binderOptions); + obj.MyDictionary = temp14; } } public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value25) + if (configuration["MyInt"] is string value15) { - obj.MyInt = ParseInt(value25, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt index 1cf54cb905bb5..e4bcaf6a9b7c9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt @@ -65,18 +65,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return ParseInt(value, () => section.Path); } - - if (type == typeof(bool?)) + else if (type == typeof(bool?)) { return ParseBool(value, () => section.Path); } - - if (type == typeof(byte[])) + else if (type == typeof(byte[])) { return ParseByteArray(value, () => section.Path); } - - if (type == typeof(CultureInfo)) + else if (type == typeof(CultureInfo)) { return ParseCultureInfo(value, () => section.Path); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt index ebf58aaae2040..85d0901de3ff6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt @@ -59,62 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new NotSupportedException($"Unable to bind to type ''{type}'': generator did not detect the type as input."); - } - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) - { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is List typedObj1) - { - BindCore(configuration, ref typedObj1, binderOptions); - return; - } - - if (obj is int[] typedObj3) - { - BindCore(configuration, ref typedObj3, binderOptions); - return; - } - - if (obj is Dictionary typedObj5) - { - BindCore(configuration, ref typedObj5, binderOptions); - return; - } - - if (obj is Program.MyClass typedObj7) - { - BindCore(configuration, ref typedObj7, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -126,25 +75,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - var temp9 = new List(); - BindCore(configuration, ref temp9, binderOptions); + var temp1 = new List(); + BindCore(configuration, ref temp1, binderOptions); int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp9.Count); - temp9.CopyTo(obj, originalCount); + Array.Resize(ref obj, originalCount + temp1.Count); + temp1.CopyTo(obj, originalCount); } public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -156,45 +95,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value12) + if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value12, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section13) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp15 = obj.MyList; - temp15 ??= new List(); - BindCore(section13, ref temp15, binderOptions); - obj.MyList = temp15; + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section16) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp18 = obj.MyArray; - temp18 ??= new int[0]; - BindCore(section16, ref temp18, binderOptions); - obj.MyArray = temp18; + int[]? temp10 = obj.MyArray; + temp10 ??= new int[0]; + BindCore(section8, ref temp10, binderOptions); + obj.MyArray = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section19) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp21 = obj.MyDictionary; - temp21 ??= new Dictionary(); - BindCore(section19, ref temp21, binderOptions); - obj.MyDictionary = temp21; + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt index a203fcc55ebcc..d394cc7b269f7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -59,62 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new NotSupportedException($"Unable to bind to type ''{type}'': generator did not detect the type as input."); - } - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) - { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is List typedObj1) - { - BindCore(configuration, ref typedObj1, binderOptions); - return; - } - - if (obj is int[] typedObj3) - { - BindCore(configuration, ref typedObj3, binderOptions); - return; - } - - if (obj is Dictionary typedObj5) - { - BindCore(configuration, ref typedObj5, binderOptions); - return; - } - - if (obj is Program.MyClass typedObj7) - { - BindCore(configuration, ref typedObj7, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -126,25 +75,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - var temp9 = new List(); - BindCore(configuration, ref temp9, binderOptions); + var temp1 = new List(); + BindCore(configuration, ref temp1, binderOptions); int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp9.Count); - temp9.CopyTo(obj, originalCount); + Array.Resize(ref obj, originalCount + temp1.Count); + temp1.CopyTo(obj, originalCount); } public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -156,45 +95,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value12) + if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value12, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section13) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp15 = obj.MyList; - temp15 ??= new List(); - BindCore(section13, ref temp15, binderOptions); - obj.MyList = temp15; + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section16) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp18 = obj.MyArray; - temp18 ??= new int[0]; - BindCore(section16, ref temp18, binderOptions); - obj.MyArray = temp18; + int[]? temp10 = obj.MyArray; + temp10 ??= new int[0]; + BindCore(section8, ref temp10, binderOptions); + obj.MyArray = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section19) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp21 = obj.MyDictionary; - temp21 ??= new Dictionary(); - BindCore(section19, ref temp21, binderOptions); - obj.MyDictionary = temp21; + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt index f0bb0023fe98a..83cd88561310a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt @@ -59,52 +59,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new NotSupportedException($"Unable to bind to type ''{type}'': generator did not detect the type as input."); - } - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) - { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is Program.MyClass2 typedObj1) - { - BindCore(configuration, ref typedObj1, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value3) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value3, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt index 5425abdfc1813..91714c80cd013 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt @@ -59,52 +59,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new NotSupportedException($"Unable to bind to type ''{type}'': generator did not detect the type as input."); - } - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) - { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is Program.MyClass2 typedObj1) - { - BindCore(configuration, ref typedObj1, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value3) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value3, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt index 99266d10a4370..88b35037c22c3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt @@ -48,8 +48,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration optionsBuilder.Configure((obj, configuration) => { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); - BindCoreMain(section, obj, configureOptions); + BindCoreMain(section, obj, typeof(TOptions), configureOptions); }); optionsBuilder.Services.AddSingleton, ConfigurationChangeTokenSource>(); @@ -60,7 +70,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { @@ -72,35 +82,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (!HasValueOrChildren(configuration)) { return; } - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (obj is Program.MyClass typedObj2) + if (type == typeof(Program.MyClass)) { - BindCore(configuration, ref typedObj2, binderOptions); + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); return; } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -112,29 +112,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value5) + if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp8 = obj.MyList; - temp8 ??= new List(); - BindCore(section6, ref temp8, binderOptions); - obj.MyList = temp8; + List? temp5 = obj.MyList; + temp5 ??= new List(); + BindCore(section3, ref temp5, binderOptions); + obj.MyList = temp5; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index 69f3645910fcd..633196e7a742d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -68,14 +68,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); } #endregion IServiceCollection extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { @@ -87,35 +87,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (!HasValueOrChildren(configuration)) { return; } - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (obj is Program.MyClass typedObj2) + if (type == typeof(Program.MyClass)) { - BindCore(configuration, ref typedObj2, binderOptions); + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); return; } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -127,29 +117,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value5) + if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp8 = obj.MyList; - temp8 ??= new List(); - BindCore(section6, ref temp8, binderOptions); - obj.MyList = temp8; + List? temp5 = obj.MyList; + temp5 ??= new List(); + BindCore(section3, ref temp5, binderOptions); + obj.MyList = temp5; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index 36d798a445581..fb5b4b4ad721d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -62,14 +62,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); } #endregion IServiceCollection extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { @@ -81,35 +81,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (!HasValueOrChildren(configuration)) { return; } - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (obj is Program.MyClass typedObj2) + if (type == typeof(Program.MyClass)) { - BindCore(configuration, ref typedObj2, binderOptions); + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); return; } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -121,29 +111,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value5) + if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp8 = obj.MyList; - temp8 ??= new List(); - BindCore(section6, ref temp8, binderOptions); - obj.MyList = temp8; + List? temp5 = obj.MyList; + temp5 ??= new List(); + BindCore(section3, ref temp5, binderOptions); + obj.MyList = temp5; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index 214cc899bef26..1bf110454ec7b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -32,13 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] - public static void Bind(this IConfiguration configuration, object? obj) => BindCoreMain(configuration, obj, configureOptions: null); - #endregion IConfiguration extensions. - - #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); - - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { if (configuration is null) { @@ -50,166 +44,154 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - - if (!HasValueOrChildren(configuration)) - { - return; - } - - if (obj is Program.MyClass typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - if (configuration["Prop0"] is string value2) + if (configuration["Prop0"] is string value0) { - obj.Prop0 = ParseBool(value2, () => configuration.GetSection("Prop0").Path); + obj.Prop0 = ParseBool(value0, () => configuration.GetSection("Prop0").Path); } - if (configuration["Prop1"] is string value3) + if (configuration["Prop1"] is string value1) { - obj.Prop1 = ParseByte(value3, () => configuration.GetSection("Prop1").Path); + obj.Prop1 = ParseByte(value1, () => configuration.GetSection("Prop1").Path); } - if (configuration["Prop2"] is string value4) + if (configuration["Prop2"] is string value2) { - obj.Prop2 = ParseSbyte(value4, () => configuration.GetSection("Prop2").Path); + obj.Prop2 = ParseSbyte(value2, () => configuration.GetSection("Prop2").Path); } - if (configuration["Prop3"] is string value5) + if (configuration["Prop3"] is string value3) { - obj.Prop3 = ParseChar(value5, () => configuration.GetSection("Prop3").Path); + obj.Prop3 = ParseChar(value3, () => configuration.GetSection("Prop3").Path); } - if (configuration["Prop4"] is string value6) + if (configuration["Prop4"] is string value4) { - obj.Prop4 = ParseDouble(value6, () => configuration.GetSection("Prop4").Path); + obj.Prop4 = ParseDouble(value4, () => configuration.GetSection("Prop4").Path); } obj.Prop5 = configuration["Prop5"]!; - if (configuration["Prop6"] is string value8) + if (configuration["Prop6"] is string value6) { - obj.Prop6 = ParseInt(value8, () => configuration.GetSection("Prop6").Path); + obj.Prop6 = ParseInt(value6, () => configuration.GetSection("Prop6").Path); } - if (configuration["Prop8"] is string value9) + if (configuration["Prop8"] is string value7) { - obj.Prop8 = ParseShort(value9, () => configuration.GetSection("Prop8").Path); + obj.Prop8 = ParseShort(value7, () => configuration.GetSection("Prop8").Path); } - if (configuration["Prop9"] is string value10) + if (configuration["Prop9"] is string value8) { - obj.Prop9 = ParseLong(value10, () => configuration.GetSection("Prop9").Path); + obj.Prop9 = ParseLong(value8, () => configuration.GetSection("Prop9").Path); } - if (configuration["Prop10"] is string value11) + if (configuration["Prop10"] is string value9) { - obj.Prop10 = ParseFloat(value11, () => configuration.GetSection("Prop10").Path); + obj.Prop10 = ParseFloat(value9, () => configuration.GetSection("Prop10").Path); } - if (configuration["Prop13"] is string value12) + if (configuration["Prop13"] is string value10) { - obj.Prop13 = ParseUshort(value12, () => configuration.GetSection("Prop13").Path); + obj.Prop13 = ParseUshort(value10, () => configuration.GetSection("Prop13").Path); } - if (configuration["Prop14"] is string value13) + if (configuration["Prop14"] is string value11) { - obj.Prop14 = ParseUint(value13, () => configuration.GetSection("Prop14").Path); + obj.Prop14 = ParseUint(value11, () => configuration.GetSection("Prop14").Path); } - if (configuration["Prop15"] is string value14) + if (configuration["Prop15"] is string value12) { - obj.Prop15 = ParseUlong(value14, () => configuration.GetSection("Prop15").Path); + obj.Prop15 = ParseUlong(value12, () => configuration.GetSection("Prop15").Path); } obj.Prop16 = configuration["Prop16"]!; - if (configuration["Prop17"] is string value16) + if (configuration["Prop17"] is string value14) { - obj.Prop17 = ParseCultureInfo(value16, () => configuration.GetSection("Prop17").Path); + obj.Prop17 = ParseCultureInfo(value14, () => configuration.GetSection("Prop17").Path); } - if (configuration["Prop19"] is string value17) + if (configuration["Prop19"] is string value15) { - obj.Prop19 = ParseDateTime(value17, () => configuration.GetSection("Prop19").Path); + obj.Prop19 = ParseDateTime(value15, () => configuration.GetSection("Prop19").Path); } - if (configuration["Prop20"] is string value18) + if (configuration["Prop20"] is string value16) { - obj.Prop20 = ParseDateTimeOffset(value18, () => configuration.GetSection("Prop20").Path); + obj.Prop20 = ParseDateTimeOffset(value16, () => configuration.GetSection("Prop20").Path); } - if (configuration["Prop21"] is string value19) + if (configuration["Prop21"] is string value17) { - obj.Prop21 = ParseDecimal(value19, () => configuration.GetSection("Prop21").Path); + obj.Prop21 = ParseDecimal(value17, () => configuration.GetSection("Prop21").Path); } - if (configuration["Prop23"] is string value20) + if (configuration["Prop23"] is string value18) { - obj.Prop23 = ParseInt(value20, () => configuration.GetSection("Prop23").Path); + obj.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); } - if (configuration["Prop24"] is string value21) + if (configuration["Prop24"] is string value19) { - obj.Prop24 = ParseDateTime(value21, () => configuration.GetSection("Prop24").Path); + obj.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); } - if (configuration["Prop25"] is string value22) + if (configuration["Prop25"] is string value20) { - obj.Prop25 = ParseUri(value22, () => configuration.GetSection("Prop25").Path); + obj.Prop25 = ParseUri(value20, () => configuration.GetSection("Prop25").Path); } - if (configuration["Prop26"] is string value23) + if (configuration["Prop26"] is string value21) { - obj.Prop26 = ParseVersion(value23, () => configuration.GetSection("Prop26").Path); + obj.Prop26 = ParseVersion(value21, () => configuration.GetSection("Prop26").Path); } - if (configuration["Prop27"] is string value24) + if (configuration["Prop27"] is string value22) { - obj.Prop27 = ParseEnum(value24, () => configuration.GetSection("Prop27").Path); + obj.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); } - if (configuration["Prop7"] is string value25) + if (configuration["Prop7"] is string value23) { - obj.Prop7 = ParseInt128(value25, () => configuration.GetSection("Prop7").Path); + obj.Prop7 = ParseInt128(value23, () => configuration.GetSection("Prop7").Path); } - if (configuration["Prop11"] is string value26) + if (configuration["Prop11"] is string value24) { - obj.Prop11 = ParseHalf(value26, () => configuration.GetSection("Prop11").Path); + obj.Prop11 = ParseHalf(value24, () => configuration.GetSection("Prop11").Path); } - if (configuration["Prop12"] is string value27) + if (configuration["Prop12"] is string value25) { - obj.Prop12 = ParseUInt128(value27, () => configuration.GetSection("Prop12").Path); + obj.Prop12 = ParseUInt128(value25, () => configuration.GetSection("Prop12").Path); } - if (configuration["Prop18"] is string value28) + if (configuration["Prop18"] is string value26) { - obj.Prop18 = ParseDateOnly(value28, () => configuration.GetSection("Prop18").Path); + obj.Prop18 = ParseDateOnly(value26, () => configuration.GetSection("Prop18").Path); } - if (configuration["Prop22"] is string value29) + if (configuration["Prop22"] is string value27) { - obj.Prop22 = ParseByteArray(value29, () => configuration.GetSection("Prop22").Path); + obj.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -232,42 +214,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static bool HasValueOrChildren(IConfiguration configuration) - { - if ((configuration as IConfigurationSection)?.Value is not null) - { - return true; - } - return AsConfigWithChildren(configuration) is not null; - } - - public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) - { - foreach (IConfigurationSection _ in configuration.GetChildren()) - { - return configuration; - } - return null; - } - - public static BinderOptions? GetBinderOptions(Action? configureOptions) - { - if (configureOptions is null) - { - return null; - } - - BinderOptions binderOptions = new(); - configureOptions(binderOptions); - - if (binderOptions.BindNonPublicProperties) - { - throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); - } - - return binderOptions; - } - public static bool ParseBool(string value, Func getPath) { try diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index 6e678300999be..7f626f0e27c52 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -53,7 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); } #endregion IServiceCollection extensions. @@ -61,7 +61,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { @@ -73,53 +73,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (!HasValueOrChildren(configuration)) { return; } - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - if (obj is Program.MyClass2 typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is List typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Dictionary typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (obj is Program.MyClass typedObj8) + if (type == typeof(Program.MyClass)) { - BindCore(configuration, ref typedObj8, binderOptions); + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); return; } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -131,26 +103,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value10) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value10, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -161,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -177,45 +134,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value13) + if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value13, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section14) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp16 = obj.MyList; - temp16 ??= new List(); - BindCore(section14, ref temp16, binderOptions); - obj.MyList = temp16; + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section17) + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp19 = obj.MyList2; - temp19 ??= new List(); - BindCore(section17, ref temp19, binderOptions); - obj.MyList2 = temp19; + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section20) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp22 = obj.MyDictionary; - temp22 ??= new Dictionary(); - BindCore(section20, ref temp22, binderOptions); - obj.MyDictionary = temp22; + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index f759068b61ae2..5848c2412f9b7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -53,7 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); } #endregion IServiceCollection extensions. @@ -61,7 +61,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { @@ -73,53 +73,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (!HasValueOrChildren(configuration)) { return; } - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - if (obj is Program.MyClass2 typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is List typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Dictionary typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (obj is Program.MyClass typedObj8) + if (type == typeof(Program.MyClass)) { - BindCore(configuration, ref typedObj8, binderOptions); + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); return; } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -131,26 +103,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value10) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value10, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -161,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -177,45 +134,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value13) + if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value13, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section14) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp16 = obj.MyList; - temp16 ??= new List(); - BindCore(section14, ref temp16, binderOptions); - obj.MyList = temp16; + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section17) + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp19 = obj.MyList2; - temp19 ??= new List(); - BindCore(section17, ref temp19, binderOptions); - obj.MyList2 = temp19; + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section20) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp22 = obj.MyDictionary; - temp22 ??= new Dictionary(); - BindCore(section20, ref temp22, binderOptions); - obj.MyDictionary = temp22; + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index 0b8103c75621c..91226d730166f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -53,7 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); } #endregion IServiceCollection extensions. @@ -61,7 +61,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { @@ -73,53 +73,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (!HasValueOrChildren(configuration)) { return; } - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - if (obj is Program.MyClass2 typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is List typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Dictionary typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (obj is Program.MyClass typedObj8) + if (type == typeof(Program.MyClass)) { - BindCore(configuration, ref typedObj8, binderOptions); + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); return; } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -131,26 +103,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value10) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value10, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -161,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -177,45 +134,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value13) + if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value13, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section14) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp16 = obj.MyList; - temp16 ??= new List(); - BindCore(section14, ref temp16, binderOptions); - obj.MyList = temp16; + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section17) + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp19 = obj.MyList2; - temp19 ??= new List(); - BindCore(section17, ref temp19, binderOptions); - obj.MyList2 = temp19; + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section20) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp22 = obj.MyDictionary; - temp22 ??= new Dictionary(); - BindCore(section20, ref temp22, binderOptions); - obj.MyDictionary = temp22; + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 53d3ee8d7d431..8c9ccaa71a779 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -47,7 +47,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); } #endregion IServiceCollection extensions. @@ -55,7 +55,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration? configuration, object? obj, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { @@ -67,53 +67,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (!HasValueOrChildren(configuration)) { return; } - if (obj is List typedObj0) - { - BindCore(configuration, ref typedObj0, binderOptions); - return; - } - - if (obj is Program.MyClass2 typedObj2) - { - BindCore(configuration, ref typedObj2, binderOptions); - return; - } - - if (obj is List typedObj4) - { - BindCore(configuration, ref typedObj4, binderOptions); - return; - } - - if (obj is Dictionary typedObj6) - { - BindCore(configuration, ref typedObj6, binderOptions); - return; - } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); - if (obj is Program.MyClass typedObj8) + if (type == typeof(Program.MyClass)) { - BindCore(configuration, ref typedObj8, binderOptions); + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); return; } - throw new NotSupportedException($"Unable to bind to type ''{obj.GetType()}'': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -125,26 +97,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value10) + if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value10, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -155,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -171,45 +128,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; - if (configuration["MyInt"] is string value13) + if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value13, () => configuration.GetSection("MyInt").Path); + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section14) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp16 = obj.MyList; - temp16 ??= new List(); - BindCore(section14, ref temp16, binderOptions); - obj.MyList = temp16; + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section17) + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp19 = obj.MyList2; - temp19 ??= new List(); - BindCore(section17, ref temp19, binderOptions); - obj.MyList2 = temp19; + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section20) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp22 = obj.MyDictionary; - temp22 ??= new Dictionary(); - BindCore(section20, ref temp22, binderOptions); - obj.MyDictionary = temp22; + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs index ad78d82f48d0f..a512c5efe495b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs @@ -62,7 +62,7 @@ public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion) Diagnostic diagnostic = Assert.Single(d); Assert.True(diagnostic.Id == "SYSLIB1102"); - Assert.Contains("C# 11", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); + Assert.Contains("C# 12", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity); } @@ -252,9 +252,9 @@ public class MyClass2 { } Assert.Single(r); string generatedSource = string.Join('\n', r[0].SourceText.Lines.Select(x => x.ToString())); - Assert.Contains("public static void Bind(this IConfiguration configuration, object? obj) => BindCoreMain(configuration, obj, configureOptions: null);", generatedSource); - Assert.Contains("public static void Bind(this IConfiguration configuration, object? obj, Action? configureOptions) => BindCoreMain(configuration, obj, configureOptions);", generatedSource); - Assert.Contains("public static void Bind(this IConfiguration configuration, string key, object? obj) => BindCoreMain(configuration?.GetSection(key), obj, configureOptions: null);", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? obj)", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? obj, Action? configureOptions)", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? obj)", generatedSource); Assert.Empty(d); } @@ -400,7 +400,7 @@ private static async Task VerifyAgainstBaselineUsingFile( LanguageVersion langVersion = LanguageVersion.Preview, IEnumerable? references = null) => await RoslynTestUtils.RunGenerator( - new ConfigurationBindingGenerator() { EmitUniqueHelperNames = false }, + new ConfigurationBindingGenerator(), references ?? s_compilationAssemblyRefs, new[] { testSourceCode }, langVersion: langVersion).ConfigureAwait(false); diff --git a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj index 5a66e45d7f83d..c0074144e78d9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj @@ -4,7 +4,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true $(Features);InterceptorsPreview - true true true Configuration support for Microsoft.Extensions.Logging. diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 978f746ab1fc9..0dceab438f82f 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -8,8 +8,8 @@ true true $(Features);InterceptorsPreview - true true + true Console logger provider implementation for Microsoft.Extensions.Logging. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs index bbbbf412c2007..8431a112d4883 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs @@ -7,7 +7,6 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using SourceGenerators; namespace Microsoft.Extensions.Options.Generators { @@ -31,15 +30,16 @@ private sealed record StaticFieldInfo(string FieldTypeFQN, int FieldOrder, strin public Emitter(Compilation compilation, bool emitPreamble = true) : base(emitPreamble) { - if (((CSharpCompilation)compilation).LanguageVersion >= Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp11) + if (((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp11) { _modifier = "file"; } else { _modifier = "internal"; - GeneratorHelpers.MakeNameUnique(ref _staticValidationAttributeHolderClassName); - GeneratorHelpers.MakeNameUnique(ref _staticValidatorHolderClassName); + string suffix = $"_{new Random().Next():X8}"; + _staticValidationAttributeHolderClassName += suffix; + _staticValidatorHolderClassName += suffix; } _staticValidationAttributeHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{_staticValidationAttributeHolderClassName}"; diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj index cd27b518a8dc4..41ceaf6739c33 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj @@ -20,7 +20,6 @@ -