提交 92959931 编写于 作者: D dotnet-bot

Merge in 'release/8.0-rc1' changes

......@@ -270,3 +270,5 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
| Suppression ID | Suppressed Diagnostic ID | Description |
| :----------------------- | :----------------------- | :---------- |
| __`SYSLIBSUPPRESS0001`__ | CA1822 | Do not offer to make methods static when the methods need to be instance methods for a custom marshaller shape. |
| __`SYSLIBSUPPRESS0002`__ | IL2026 | ConfigurationBindingGenerator: suppress RequiresUnreferencedCode diagnostic for binding call that has been intercepted by a generated static variant. |
| __`SYSLIBSUPPRESS0003`__ | IL3050 | ConfigurationBindingGenerator: suppress RequiresDynamicCode diagnostic for binding call that has been intercepted by a generated static variant. |
......@@ -10,6 +10,7 @@
<UsagePattern IdentityGlob="System.Composition*/*7.*" />
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.4.*" />
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.5.*" />
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.7.*" />
<!-- Allowed and pinned to major version due to https://github.com/dotnet/source-build/issues/3228 -->
<UsagePattern IdentityGlob="Microsoft.NETCore.App.Crossgen2.linux-x64/*8.*" />
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
......@@ -17,7 +18,6 @@ private sealed partial class Emitter
private readonly SourceGenerationSpec _sourceGenSpec;
private bool _emitBlankLineBeforeNextStatement;
private bool _useFullyQualifiedNames;
private int _valueSuffixIndex;
private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]"));
......@@ -32,7 +32,7 @@ public Emitter(SourceProductionContext context, SourceGenerationSpec sourceGenSp
public void Emit()
{
if (!ShouldEmitBinders())
if (!ShouldEmitBindingExtensions())
{
return;
}
......@@ -42,17 +42,26 @@ public void Emit()
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
""");
_writer.WriteLine();
_useFullyQualifiedNames = true;
EmitBinder_Extensions_IConfiguration();
EmitBinder_Extensions_OptionsBuilder();
EmitBinder_Extensions_IServiceCollection();
EmitInterceptsLocationAttrDecl();
EmitStartBlock($"namespace {ProjectName}");
EmitUsingStatements();
_writer.WriteLine();
EmitStartBlock($$"""
{{Expression.GeneratedCodeAnnotation}}
file static class {{Identifier.BindingExtensions}}
""");
EmitBindingExtensions_IConfiguration();
EmitBindingExtensions_OptionsBuilder();
EmitBindingExtensions_IServiceCollection();
EmitCoreBindingHelpers();
EmitEndBlock(); // BindingExtensions class
_useFullyQualifiedNames = false;
Emit_CoreBindingHelper();
EmitEndBlock(); // Binding namespace.
_context.AddSource($"{Identifier.GeneratedConfigurationBinder}.g.cs", _writer.ToSourceText());
_context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText());
}
private void EmitBindCoreCall(
......@@ -74,7 +83,7 @@ public void Emit()
if (initKind is InitializationKind.AssignmentWithNullCheck)
{
Debug.Assert(!type.IsValueType);
_writer.WriteLine($"{type.MinimalDisplayString}? {tempIdentifier} = {memberAccessExpr};");
_writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};");
EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck);
}
else if (initKind is InitializationKind.None && type.IsValueType)
......@@ -89,9 +98,7 @@ public void Emit()
void EmitBindCoreCall(string objExpression, InitializationKind initKind)
{
string methodDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCore));
string bindCoreCall = $@"{methodDisplayString}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
EmitObjectInit(objExpression, initKind);
_writer.WriteLine(bindCoreCall);
writeOnSuccess?.Invoke(objExpression);
......@@ -127,12 +134,11 @@ void EmitObjectInit(string objExpression, InitializationKind initKind)
}
else if (typeKind is StringParsableTypeKind.Enum)
{
parsedValueExpr = $"ParseEnum<{type.MinimalDisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
parsedValueExpr = $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
}
else
{
string helperMethodDisplayString = GetHelperMethodDisplayString(type.ParseMethodName);
parsedValueExpr = $"{helperMethodDisplayString}({stringValueToParse_Expr}, () => {sectionPathExpr})";
parsedValueExpr = $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})";
}
if (!checkForNullSectionValue)
......@@ -156,7 +162,7 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati
string initExpr;
CollectionSpec? collectionType = type as CollectionSpec;
string effectiveDisplayString = GetTypeDisplayString(type);
string effectiveDisplayString = type.DisplayString;
if (collectionType is not null)
{
if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array })
......@@ -165,7 +171,7 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati
}
else
{
effectiveDisplayString = GetTypeDisplayString(collectionType.ConcreteType ?? collectionType);
effectiveDisplayString = (collectionType.ConcreteType ?? collectionType).DisplayString;
initExpr = $"new {effectiveDisplayString}()";
}
}
......@@ -215,36 +221,41 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati
return true;
}
private void EmitCastToIConfigurationSection()
private void EmitInterceptsLocationAttrDecl()
{
string sectionTypeDisplayString;
string exceptionTypeDisplayString;
if (_useFullyQualifiedNames)
{
sectionTypeDisplayString = "global::Microsoft.Extensions.Configuration.IConfigurationSection";
exceptionTypeDisplayString = FullyQualifiedDisplayString.InvalidOperationException;
}
else
{
sectionTypeDisplayString = Identifier.IConfigurationSection;
exceptionTypeDisplayString = nameof(InvalidOperationException);
}
_writer.WriteLine();
_writer.WriteLine($$"""
if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}})
namespace System.Runtime.CompilerServices
{
throw new {{exceptionTypeDisplayString}}();
using System;
using System.CodeDom.Compiler;
{{Expression.GeneratedCodeAnnotation}}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
""");
_writer.WriteLine();
}
private void EmitUsingStatements()
{
foreach (string @namespace in _sourceGenSpec.Namespaces.ToImmutableSortedSet())
{
_writer.WriteLine($"using {@namespace};");
}
}
private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn)
{
string returnPostfix = voidReturn ? string.Empty : " null";
string methodDisplayString = GetHelperMethodDisplayString(Identifier.HasValueOrChildren);
_writer.WriteLine($$"""
if (!{{methodDisplayString}}({{Identifier.configuration}}))
if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}}))
{
return{{returnPostfix}};
}
......
// 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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Operations;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
......@@ -147,7 +149,7 @@ private static bool IsValidRootConfigType(ITypeSymbol? type)
{
// List<string> is used in generated code as a temp holder for formatting
// an error for config properties that don't map to object properties.
_sourceGenSpec.TypeNamespaces.Add("System.Collections.Generic");
_sourceGenSpec.Namespaces.Add("System.Collections.Generic");
spec = CreateObjectSpec(namedType);
}
......@@ -169,32 +171,54 @@ private static bool IsValidRootConfigType(ITypeSymbol? type)
string @namespace = spec.Namespace;
if (@namespace is not null and not "<global namespace>")
{
_sourceGenSpec.TypeNamespaces.Add(@namespace);
_sourceGenSpec.Namespaces.Add(@namespace);
}
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<TypeSpec>? types))
if (typeSpec.NeedsMemberBinding)
{
_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet<TypeSpec>();
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, typeSpec);
RegisterTypeForBindCoreGen(typeSpec);
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren;
}
types.Add(type);
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
}
private void RegisterTypeForBindCoreUntypedGen(TypeSpec typeSpec)
private void RegisterTypeForBindCoreGen(TypeSpec typeSpec)
{
if (typeSpec.NeedsMemberBinding)
{
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, typeSpec);
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreUntyped, typeSpec);
}
}
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.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet<TypeSpec>? types))
{
_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet<TypeSpec>();
}
types.Add(type);
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
}
/// <summary>
/// Registers interceptors for root binding methods, except for ConfigurationBinder.Bind,
/// which is handled by <see cref="RegisterAsInterceptor_ConfigBinder_BindMethod"/>
/// </summary>
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 &&
......@@ -335,7 +359,7 @@ private bool TryGetTypeSpec(ITypeSymbol type, DiagnosticDescriptor descriptor, o
// We want a BindCore method for List<TElement> as a temp holder for the array values. We know the element type is supported.
EnumerableSpec listSpec = (GetOrCreateTypeSpec(_typeSymbols.List.Construct(arrayType.ElementType)) as EnumerableSpec)!;
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, listSpec);
RegisterTypeForBindCoreGen(listSpec);
EnumerableSpec spec = new EnumerableSpec(arrayType)
{
......@@ -347,7 +371,7 @@ private bool TryGetTypeSpec(ITypeSymbol type, DiagnosticDescriptor descriptor, o
};
Debug.Assert(spec.CanInitialize);
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
RegisterTypeForBindCoreGen(spec);
return spec;
}
......@@ -383,7 +407,7 @@ private bool IsSupportedArrayType(ITypeSymbol type)
if (spec is not null)
{
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
RegisterTypeForBindCoreGen(spec);
spec.InitExceptionMessage ??= spec.ElementType.InitExceptionMessage;
}
......@@ -442,7 +466,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k
constructionStrategy = InitializationStrategy.ToEnumerableMethod;
populationStrategy = CollectionPopulationStrategy.Cast_Then_Add;
toEnumerableMethodCall = "ToDictionary(pair => pair.Key, pair => pair.Value)";
_sourceGenSpec.TypeNamespaces.Add("System.Linq");
_sourceGenSpec.Namespaces.Add("System.Linq");
}
else
{
......@@ -711,7 +735,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k
if (objectSpec.NeedsMemberBinding)
{
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, objectSpec);
RegisterTypeForBindCoreGen(objectSpec);
}
return objectSpec;
......@@ -890,4 +914,19 @@ private void RegisterTypeDiagnostic(ITypeSymbol causingType, InvocationDiagnosti
}
}
}
public static class ParserExtensions
{
public static void RegisterCacheEntry<TKey, TValue, TEntry>(this Dictionary<TKey, TValue> cache, TKey key, TEntry entry)
where TKey : notnull
where TValue : ICollection<TEntry>, new()
{
if (!cache.TryGetValue(key, out TValue? entryCollection))
{
cache[key] = entryCollection = new TValue();
}
entryCollection.Add(entry);
}
}
}
// 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.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
public sealed partial class ConfigurationBindingGenerator
{
/// <summary>
/// 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.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class Suppressor : DiagnosticSuppressor
{
private const string Justification = "The target method has been intercepted by a generated static variant.";
/// <summary>
/// Suppression descriptor for IL2026: Members attributed with RequiresUnreferencedCode may break when trimming.
/// </summary>
private static readonly SuppressionDescriptor RUCDiagnostic = new(id: "SYSLIBSUPPRESS0002", suppressedDiagnosticId: "IL2026", Justification);
/// <summary>
/// Suppression descriptor for IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as native AOT.
/// </summary>
private static readonly SuppressionDescriptor RDCDiagnostic = new(id: "SYSLIBSUPPRESS0003", suppressedDiagnosticId: "IL3050", Justification);
public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => ImmutableArray.Create(RUCDiagnostic, RDCDiagnostic);
public override void ReportSuppressions(SuppressionAnalysisContext context)
{
foreach (Diagnostic diagnostic in context.ReportedDiagnostics)
{
string diagnosticId = diagnostic.Id;
if (diagnosticId != RDCDiagnostic.SuppressedDiagnosticId && diagnosticId != RUCDiagnostic.SuppressedDiagnosticId)
{
continue;
}
Location location = diagnostic.AdditionalLocations.Count > 0
? diagnostic.AdditionalLocations[0]
: diagnostic.Location;
bool shouldSuppressDiagnostic =
location.SourceTree is SyntaxTree sourceTree &&
sourceTree.GetRoot().FindNode(location.SourceSpan) is SyntaxNode syntaxNode &&
BinderInvocation.IsCandidateSyntaxNode(syntaxNode) &&
context.GetSemanticModel(sourceTree)
.GetOperation((InvocationExpressionSyntax)syntaxNode, context.CancellationToken) is IInvocationOperation operation &&
BinderInvocation.IsBindingOperation(operation);
if (shouldSuppressDiagnostic)
{
SuppressionDescriptor targetSuppression = diagnosticId == RUCDiagnostic.SuppressedDiagnosticId
? RUCDiagnostic
: RDCDiagnostic;
context.ReportSuppression(Suppression.Create(targetSuppression, diagnostic));
}
}
}
}
}
}
......@@ -5,7 +5,6 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
......@@ -15,7 +14,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
[Generator]
public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator
{
internal const string ProjectName = "Microsoft.Extensions.Configuration.Binder.SourceGeneration";
private static readonly string ProjectName = Emitter.s_assemblyName.Name;
public void Initialize(IncrementalGeneratorInitializationContext context)
{
......@@ -42,9 +41,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc));
}
/// <summary>
/// Generates source code to optimize binding with ConfigurationBinder.
/// </summary>
private static void Execute(CompilationData compilationData, ImmutableArray<BinderInvocation> inputCalls, SourceProductionContext context)
{
if (inputCalls.IsDefaultOrEmpty)
......@@ -73,7 +69,11 @@ private sealed record CompilationData
public CompilationData(CSharpCompilation compilation)
{
LanguageVersionIsSupported = compilation.LanguageVersion >= LanguageVersion.CSharp11;
// 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);
......
......@@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis;
using SourceGenerators;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
......@@ -14,91 +12,84 @@ private sealed partial class Emitter
{
private bool ShouldEmitMethods(MethodsToGen_ConfigurationBinder methods) => (_sourceGenSpec.MethodsToGen_ConfigurationBinder & methods) != 0;
private void EmitBinder_Extensions_IConfiguration()
private void EmitBindingExtensions_IConfiguration()
{
Debug.Assert(_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Count <= 3 &&
!_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Keys.Any(overload => (overload & MethodsToGen_ConfigurationBinder.Bind) is 0));
if (!ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any))
{
return;
}
_emitBlankLineBeforeNextStatement = false;
EmitRootBindingClassStartBlock(Identifier.GeneratedConfigurationBinder);
EmitBindingExtStartRegion(Identifier.IConfiguration);
EmitGetMethods();
EmitGetValueMethods();
EmitBindMethods_ConfigurationBinder();
EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
EmitBindingExtEndRegion();
}
private void EmitGetMethods()
{
const string expressionForGetCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetCore)}";
const string expressionForGetCore = nameof(MethodsToGen_CoreBindingHelper.GetCore);
const string documentation = "Attempts to bind the configuration instance to a new instance of type T.";
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T))
{
StartMethodDefinition(documentation);
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T, documentation);
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {Identifier.IConfiguration} {Identifier.configuration}) => " +
$"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}: null) ?? default(T));");
}
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions))
{
StartMethodDefinition(documentation);
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions, documentation);
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " +
$"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}) ?? default(T));");
}
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf))
{
StartMethodDefinition(documentation);
_writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf, documentation);
_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(documentation);
_writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions, documentation);
_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});");
}
}
private void EmitGetValueMethods()
{
const string expressionForGetValueCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}";
const string expressionForGetValueCore = $"{Identifier.BindingExtensions}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}";
const string documentation = "Extracts the value with the specified key and converts it to the specified type.";
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key))
{
StartMethodDefinition(documentation);
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key, documentation);
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " +
$"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? default(T));");
}
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue))
{
StartMethodDefinition(documentation);
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue, documentation);
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " +
$"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? {Identifier.defaultValue});");
}
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key))
{
StartMethodDefinition(documentation);
_writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key, documentation);
_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(documentation);
_writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " +
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue, documentation);
_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};");
}
}
......@@ -110,72 +101,71 @@ private void EmitBindMethods_ConfigurationBinder()
return;
}
Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods;
string objParamExpr = $"object? {Identifier.obj}";
if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance, out HashSet<TypeSpec>? typeSpecs))
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance))
{
foreach (TypeSpec type in typeSpecs)
{
EmitMethodImplementation(
type,
additionalParams: GetObjParameter(type),
configExpression: Identifier.configuration,
configureOptions: false);
}
EmitMethods(
MethodsToGen_ConfigurationBinder.Bind_instance,
additionalParams: objParamExpr,
configExpression: Identifier.configuration,
configureOptions: false);
}
if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions, out typeSpecs))
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions))
{
foreach (TypeSpec type in typeSpecs)
{
EmitMethodImplementation(
type,
additionalParams: $"{GetObjParameter(type)}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}",
configExpression: Identifier.configuration,
configureOptions: true);
}
EmitMethods(
MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions,
additionalParams: $"{objParamExpr}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}",
configExpression: Identifier.configuration,
configureOptions: true);
}
if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_key_instance, out typeSpecs))
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_key_instance))
{
foreach (TypeSpec type in typeSpecs)
{
EmitMethodImplementation(
type,
additionalParams: $"string {Identifier.key}, {GetObjParameter(type)}",
configExpression: $"{Expression.configurationGetSection}({Identifier.key})",
configureOptions: false);
}
EmitMethods(
MethodsToGen_ConfigurationBinder.Bind_key_instance,
additionalParams: $"string {Identifier.key}, {objParamExpr}",
configExpression: $"{Expression.configurationGetSection}({Identifier.key})",
configureOptions: false);
}
void EmitMethodImplementation(TypeSpec type, string additionalParams, string configExpression, bool configureOptions)
void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParams, string configExpression, bool configureOptions)
{
string binderOptionsArg = configureOptions ? $"{Expression.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null";
string returnExpression;
if (type.CanInitialize)
foreach (KeyValuePair<TypeSpec, List<InterceptorLocationInfo>> pair in _sourceGenSpec.InterceptionInfo_ConfigBinder.GetOverloadInfo(method))
{
returnExpression = type.NeedsMemberBinding
? $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configExpression}, ref {Identifier.obj}, {binderOptionsArg})"
: "{ }";
(TypeSpec type, List<InterceptorLocationInfo> interceptorInfoList) = (pair.Key, pair.Value);
EmitBlankLineIfRequired();
_writer.WriteLine($"/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>");
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();
}
else
{
returnExpression = GetInitException(type.InitExceptionMessage);
}
StartMethodDefinition("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 {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {additionalParams}) => "
+ $"{returnExpression};");
}
string GetObjParameter(TypeSpec type) => $"{type.FullyQualifiedDisplayString} {Identifier.obj}";
}
private void StartMethodDefinition(string documentation)
private void StartMethodDefinition(MethodsToGen_ConfigurationBinder method, string documentation)
{
EmitBlankLineIfRequired();
_writer.WriteLine($"/// <summary>{documentation}</summary>");
EmitInterceptsLocationAnnotations(method);
}
}
}
......
// 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.Generic;
using System.Diagnostics;
using System.Reflection;
......@@ -10,7 +12,9 @@ public sealed partial class ConfigurationBindingGenerator
{
private sealed partial class Emitter
{
private static readonly AssemblyName s_assemblyName = typeof(Emitter).Assembly.GetName();
private string? _emittedExtsTargetType;
internal static readonly AssemblyName s_assemblyName = typeof(ConfigurationBindingGenerator).Assembly.GetName();
private enum InitializationKind
{
......@@ -26,29 +30,13 @@ private static class Expression
public const string sectionPath = "section.Path";
public const string sectionValue = "section.Value";
public const string GetBinderOptions = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{Identifier.GetBinderOptions}";
}
private static class FullyQualifiedDisplayString
{
public const string ActionOfBinderOptions = $"global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>";
public const string AddSingleton = $"{ServiceCollectionServiceExtensions}.AddSingleton";
public const string ConfigurationChangeTokenSource = "global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource";
public const string CoreBindingHelper = $"global::{ProjectName}.{Identifier.CoreBindingHelper}";
public const string IConfiguration = "global::Microsoft.Extensions.Configuration.IConfiguration";
public const string IConfigurationSection = IConfiguration + "Section";
public const string IOptionsChangeTokenSource = "global::Microsoft.Extensions.Options.IOptionsChangeTokenSource";
public const string InvalidOperationException = "global::System.InvalidOperationException";
public const string IServiceCollection = "global::Microsoft.Extensions.DependencyInjection.IServiceCollection";
public const string NotSupportedException = "global::System.NotSupportedException";
public const string OptionsBuilderOfTOptions = $"global::Microsoft.Extensions.Options.OptionsBuilder<{Identifier.TOptions}>";
public const string ServiceCollectionServiceExtensions = "global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions";
public const string Type = $"global::System.Type";
public static string GeneratedCodeAnnotation = $@"[GeneratedCode(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]";
}
private static class MinimalDisplayString
private static class TypeDisplayString
{
public const string NullableActionOfBinderOptions = "Action<BinderOptions>?";
public const string OptionsBuilderOfTOptions = $"OptionsBuilder<{Identifier.TOptions}>";
public const string HashSetOfString = "HashSet<string>";
public const string LazyHashSetOfString = "Lazy<HashSet<string>>";
public const string ListOfString = "List<string>";
......@@ -75,6 +63,7 @@ private static class Identifier
public const string services = nameof(services);
public const string temp = nameof(temp);
public const string type = nameof(type);
public const string typedObj = nameof(typedObj);
public const string validateKeys = nameof(validateKeys);
public const string value = nameof(value);
......@@ -82,21 +71,19 @@ 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 BinderOptions = nameof(BinderOptions);
public const string BindingExtensions = nameof(BindingExtensions);
public const string ConfigurationChangeTokenSource = nameof(ConfigurationChangeTokenSource);
public const string Configure = nameof(Configure);
public const string CopyTo = nameof(CopyTo);
public const string ContainsKey = nameof(ContainsKey);
public const string CoreBindingHelper = nameof(CoreBindingHelper);
public const string Count = nameof(Count);
public const string CultureInfo = nameof(CultureInfo);
public const string CultureNotFoundException = nameof(CultureNotFoundException);
public const string Enum = nameof(Enum);
public const string ErrorOnUnknownConfiguration = nameof(ErrorOnUnknownConfiguration);
public const string GeneratedConfigurationBinder = nameof(GeneratedConfigurationBinder);
public const string GeneratedOptionsBuilderBinder = nameof(GeneratedOptionsBuilderBinder);
public const string GeneratedServiceCollectionBinder = nameof(GeneratedServiceCollectionBinder);
public const string Exception = nameof(Exception);
public const string Get = nameof(Get);
public const string GetBinderOptions = nameof(GetBinderOptions);
public const string GetChildren = nameof(GetChildren);
......@@ -108,9 +95,13 @@ private static class Identifier
public const string IConfiguration = nameof(IConfiguration);
public const string IConfigurationSection = nameof(IConfigurationSection);
public const string Int32 = "int";
public const string InterceptsLocation = nameof(InterceptsLocation);
public const string InvalidOperationException = nameof(InvalidOperationException);
public const string InvariantCulture = nameof(InvariantCulture);
public const string IOptionsChangeTokenSource = nameof(IOptionsChangeTokenSource);
public const string IServiceCollection = nameof(IServiceCollection);
public const string Length = nameof(Length);
public const string NumberStyles = nameof(NumberStyles);
public const string Parse = nameof(Parse);
public const string Path = nameof(Path);
public const string Resize = nameof(Resize);
......@@ -118,17 +109,66 @@ 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);
public const string Value = nameof(Value);
}
private bool ShouldEmitBinders() =>
private bool ShouldEmitBindingExtensions() =>
ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any) ||
ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any) ||
ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any);
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.InterceptionInfo.TryGetValue(generatedBindingOverload, out List<InterceptorLocationInfo>? infoList);
Debug.Assert(interceptsCalls ||
generatedBindingOverload is MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions ||
generatedBindingOverload is MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions);
if (interceptsCalls)
{
EmitInterceptsLocationAnnotations(infoList);
}
}
private void EmitInterceptsLocationAnnotations(List<InterceptorLocationInfo> infoList)
{
foreach (InterceptorLocationInfo info in infoList)
{
_writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]");
}
}
private void EmitBindingExtStartRegion(string targetType)
{
Debug.Assert(_emittedExtsTargetType is null);
EmitBlankLineIfRequired();
_emittedExtsTargetType = targetType;
EmitBindingExtRegionText(isStart: true);
_emitBlankLineBeforeNextStatement = false;
}
private void EmitBindingExtEndRegion()
{
Debug.Assert(_emittedExtsTargetType is not null);
EmitBindingExtRegionText(isStart: false);
_emittedExtsTargetType = null;
_emitBlankLineBeforeNextStatement = true;
}
private void EmitBindingExtRegionText(bool isStart)
{
string endSource = isStart ? string.Empty : "end";
_writer.WriteLine($"#{endSource}region {_emittedExtsTargetType} extensions.");
}
/// <summary>
/// Starts a block of source code.
/// </summary>
......@@ -171,24 +211,12 @@ private void EmitBlankLineIfRequired()
_emitBlankLineBeforeNextStatement = true;
}
private void EmitCheckForNullArgument_WithBlankLine_IfRequired(bool isValueType)
{
if (!isValueType)
{
EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
}
}
private void EmitCheckForNullArgument_WithBlankLine(string paramName)
{
string exceptionTypeDisplayString = _useFullyQualifiedNames
? "global::System.ArgumentNullException"
: "ArgumentNullException";
_writer.WriteLine($$"""
if ({{paramName}} is null)
{
throw new {{exceptionTypeDisplayString}}(nameof({{paramName}}));
throw new ArgumentNullException(nameof({{paramName}}));
}
""");
......@@ -201,51 +229,28 @@ private bool EmitInitException(TypeSpec type)
if (!type.CanInitialize)
{
_writer.WriteLine(GetInitException(type.InitExceptionMessage) + ";");
_writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{type.InitExceptionMessage}"");");
return true;
}
return false;
}
private void EmitRootBindingClassStartBlock(string className)
{
EmitBlankLineIfRequired();
EmitStartBlock($$"""
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
{{GetGeneratedCodeAttributeSrc()}}
internal static class {{className}}
""");
_emitBlankLineBeforeNextStatement = false;
}
private string GetGeneratedCodeAttributeSrc()
{
string attributeRefExpr = _useFullyQualifiedNames ? $"global::System.CodeDom.Compiler.GeneratedCodeAttribute" : "GeneratedCode";
return $@"[{attributeRefExpr}(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]";
}
private string GetInitException(string message) => $@"throw new {GetInvalidOperationDisplayName()}(""{message}"")";
private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}";
private string GetInitalizeMethodDisplayString(ObjectSpec type) =>
GetHelperMethodDisplayString($"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayStringWithoutSpecialCharacters}");
private string GetTypeDisplayString(TypeSpec type) => _useFullyQualifiedNames ? type.FullyQualifiedDisplayString : type.MinimalDisplayString;
private string GetHelperMethodDisplayString(string methodName)
{
if (_useFullyQualifiedNames)
{
methodName = FullyQualifiedDisplayString.CoreBindingHelper + "." + methodName;
}
return methodName;
}
private string GetInvalidOperationDisplayName() => _useFullyQualifiedNames ? FullyQualifiedDisplayString.InvalidOperationException : Identifier.InvalidOperationException;
private static string GetInitalizeMethodDisplayString(ObjectSpec type) =>
$"{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);
}
}
......@@ -9,19 +9,17 @@ private sealed partial class Emitter
{
private bool ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder methods) => (_sourceGenSpec.MethodsToGen_OptionsBuilderExt & methods) != 0;
private void EmitBinder_Extensions_OptionsBuilder()
private void EmitBindingExtensions_OptionsBuilder()
{
if (!ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any))
{
return;
}
EmitRootBindingClassStartBlock(Identifier.GeneratedOptionsBuilderBinder);
EmitBindingExtStartRegion(TypeDisplayString.OptionsBuilderOfTOptions);
EmitBindMethods_Extensions_OptionsBuilder();
EmitBindConfigurationMethod();
EmitEndBlock();
EmitBindingExtEndRegion();
}
private void EmitBindMethods_Extensions_OptionsBuilder()
......@@ -32,24 +30,25 @@ private void EmitBindMethods_Extensions_OptionsBuilder()
}
const string documentation = @"/// <summary>Registers a configuration instance which <typeparamref name=""TOptions""/> will bind against.</summary>";
const string paramList = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}";
const string paramList = $"{Identifier.IConfiguration} {Identifier.configuration}";
if (ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Bind_T))
{
EmitMethodStartBlock("Bind", paramList, documentation);
_writer.WriteLine($"return global::{Identifier.GeneratedOptionsBuilderBinder}.Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.Bind_T, "Bind", paramList, documentation);
_writer.WriteLine($"return Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
EmitEndBlock();
}
EmitMethodStartBlock(
MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions,
"Bind",
paramList + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}",
paramList + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}",
documentation);
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
_writer.WriteLine($$"""
global::{{Identifier.GeneratedServiceCollectionBinder}}.{{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}});
{{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}});
return {{Identifier.optionsBuilder}};
""");
......@@ -63,19 +62,20 @@ private void EmitBindConfigurationMethod()
return;
}
const string documentation = $@"/// <summary>Registers the dependency injection container to bind <typeparamref name=""TOptions""/> against the <see cref=""{FullyQualifiedDisplayString.IConfiguration}""/> obtained from the DI service provider.</summary>";
string paramList = $"string {Identifier.configSectionPath}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions} = null";
const string documentation = $@"/// <summary>Registers the dependency injection container to bind <typeparamref name=""TOptions""/> against the <see cref=""{Identifier.IConfiguration}""/> obtained from the DI service provider.</summary>";
string paramList = $"string {Identifier.configSectionPath}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions} = null";
EmitMethodStartBlock("BindConfiguration", paramList, documentation);
EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration, "BindConfiguration", paramList, documentation);
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath);
EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{FullyQualifiedDisplayString.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
_writer.WriteLine($$"""
{{FullyQualifiedDisplayString.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, global::System.StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
{{FullyQualifiedDisplayString.CoreBindingHelper}}.{{nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
{{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
{{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
""");
EmitEndBlock(endBraceTrailingSource: ");");
......@@ -83,20 +83,20 @@ private void EmitBindConfigurationMethod()
_writer.WriteLine();
_writer.WriteLine($$"""
{{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.optionsBuilder}}.{{Identifier.Services}});
{{Identifier.optionsBuilder}}.{{Identifier.Services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>();
return {{Identifier.optionsBuilder}};
""");
EmitEndBlock();
}
private void EmitMethodStartBlock(string methodName, string paramList, string documentation)
private void EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder method, string methodName, string paramList, string documentation)
{
paramList = $"this {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}";
paramList = $"this {TypeDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}";
EmitBlankLineIfRequired();
_writer.WriteLine(documentation);
EmitStartBlock($"public static {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
EmitInterceptsLocationAnnotations(method);
EmitStartBlock($"public static {TypeDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
}
}
}
......
......@@ -9,71 +9,72 @@ private sealed partial class Emitter
{
private bool ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection methods) => (_sourceGenSpec.MethodsToGen_ServiceCollectionExt & methods) != 0;
private void EmitBinder_Extensions_IServiceCollection()
private void EmitBindingExtensions_IServiceCollection()
{
if (!ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any))
{
return;
}
EmitRootBindingClassStartBlock(Identifier.GeneratedServiceCollectionBinder);
EmitBindingExtStartRegion(Identifier.IServiceCollection);
EmitConfigureMethods();
EmitBindingExtEndRegion();
}
private void EmitConfigureMethods()
{
const string defaultNameExpr = "string.Empty";
const string configureMethodString = $"global::{Identifier.GeneratedServiceCollectionBinder}.{Identifier.Configure}";
string configParam = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}";
string configParam = $"{Identifier.IConfiguration} {Identifier.configuration}";
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T))
{
EmitStartMethod(configParam);
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T, configParam);
_writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
EmitEndBlock();
}
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_name))
{
EmitStartMethod(
MethodsToGen_Extensions_ServiceCollection.Configure_T_name,
paramList: $"string? {Identifier.name}, " + configParam);
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
_writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
EmitEndBlock();
}
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions))
{
EmitStartMethod(
paramList: configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});");
MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions,
paramList: configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}");
_writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});");
EmitEndBlock();
}
// Core Configure method that the other overloads call.
// Like the others, it is public API that could be called directly by users.
// So, it is always generated whenever a Configure overload is called.
string optionsNamespaceName = "global::Microsoft.Extensions.Options";
string bindCoreUntypedDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped));
string optionsNamespaceName = "Microsoft.Extensions.Options";
EmitStartMethod(paramList: $"string? {Identifier.name}, " + configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, paramList: $"string? {Identifier.name}, " + configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}");
EmitCheckForNullArgument_WithBlankLine(Identifier.services);
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
_writer.WriteLine($$"""
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}});
{{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}}));
return {{FullyQualifiedDisplayString.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{bindCoreUntypedDisplayString}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}})));
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}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}){{Identifier.configureOptions}})));
""");
EmitEndBlock();
EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
}
private void EmitStartMethod(string paramList)
private void EmitStartMethod(MethodsToGen_Extensions_ServiceCollection overload, string paramList)
{
paramList = $"this {FullyQualifiedDisplayString.IServiceCollection} {Identifier.services}, {paramList}";
paramList = $"this {Identifier.IServiceCollection} {Identifier.services}, {paramList}";
EmitBlankLineIfRequired();
EmitStartBlock($$"""
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static {{FullyQualifiedDisplayString.IServiceCollection}} {{Identifier.Configure}}<{{Identifier.TOptions}}>({{paramList}}) where {{Identifier.TOptions}} : class
""");
_writer.WriteLine("/// <summary>Registers a configuration instance which TOptions will bind against.</summary>");
EmitInterceptsLocationAnnotations(overload);
EmitStartBlock($"public static {Identifier.IServiceCollection} {Identifier.Configure}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
}
}
}
......
// 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;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
internal sealed record InterceptorLocationInfo
{
public InterceptorLocationInfo(IInvocationOperation operation)
{
SyntaxNode operationSyntax = operation.Syntax;
TextSpan operationSpan = operationSyntax.Span;
SyntaxTree operationSyntaxTree = operationSyntax.SyntaxTree;
FilePath = GetInterceptorFilePath(operationSyntaxTree, operation.SemanticModel?.Compilation.Options.SourceReferenceResolver);
FileLinePositionSpan span = operationSyntaxTree.GetLineSpan(operationSpan);
LineNumber = span.StartLinePosition.Line + 1;
// Calculate the character offset to the end of the binding invocation detected.
int invocationLength = ((MemberAccessExpressionSyntax)((InvocationExpressionSyntax)operationSyntax).Expression).Expression.Span.Length;
CharacterNumber = span.StartLinePosition.Character + invocationLength + 2;
}
public string FilePath { get; }
public int LineNumber { get; }
public int CharacterNumber { get; }
// Utilize the same logic used by the interceptors API for resolving the source mapped value of a path.
// https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064
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<KeyValuePair<TypeSpec, List<InterceptorLocationInfo>>>
{
private readonly Dictionary<TypeSpec, List<InterceptorLocationInfo>> _typeInterceptionInfo = new();
public void RegisterLocationInfo(TypeSpec type, IInvocationOperation operation) =>
_typeInterceptionInfo.RegisterCacheEntry(type, new InterceptorLocationInfo(operation));
public IEnumerator<KeyValuePair<TypeSpec, List<InterceptorLocationInfo>>> GetEnumerator() => _typeInterceptionInfo.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
......@@ -10,11 +10,12 @@ public enum MethodsToGen_CoreBindingHelper
{
None = 0x0,
BindCore = 0x1,
BindCoreUntyped = 0x2,
GetCore = 0x4,
GetValueCore = 0x8,
GetCore = 0x2,
GetValueCore = 0x4,
BindCoreMain = 0x8,
Initialize = 0x10,
AsConfigWithChildren = 0x20,
HasValueOrChildren = 0x20,
AsConfigWithChildren = 0x40,
}
/// <summary>
......
......@@ -40,7 +40,7 @@ public static bool IsCandidateSyntaxNode(SyntaxNode node)
IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name);
}
private static bool IsBindingOperation(IInvocationOperation operation)
public static bool IsBindingOperation(IInvocationOperation operation)
{
if (operation.TargetMethod is not IMethodSymbol
{
......
......@@ -102,15 +102,7 @@ private void RegisterBindInvocation(BinderInvocation invocation)
if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
{
Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods;
if (!types.TryGetValue(overload, out HashSet<TypeSpec>? typeSpecs))
{
types[overload] = typeSpecs = new HashSet<TypeSpec>();
}
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
typeSpecs.Add(typeSpec);
RegisterAsInterceptor_ConfigBinder_BindMethod(overload, typeSpec, invocation.Operation);
}
static ITypeSymbol? ResolveType(IOperation conversionOperation) =>
......@@ -184,8 +176,8 @@ private void RegisterGetInvocation(BinderInvocation invocation)
if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec)
{
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec);
RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation);
RegisterTypeForGetCoreGen(typeSpec);
}
}
......@@ -253,10 +245,27 @@ private void RegisterGetValueInvocation(BinderInvocation invocation)
if (IsParsableFromString(effectiveType, out _) &&
GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
{
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation);
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec);
}
}
private void RegisterAsInterceptor_ConfigBinder(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation)
{
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
RegisterAsInterceptor(overload, operation);
}
/// <summary>
/// Registers generated Bind methods as interceptors. This is done differently from other root
/// methods <see cref="RegisterAsInterceptor(Enum, IInvocationOperation)"/> because we need to
/// explicitly account for the type to bind, to avoid type-check issues for polymorphic objects.
/// </summary>
private void RegisterAsInterceptor_ConfigBinder_BindMethod(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation)
{
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
_sourceGenSpec.InterceptionInfo_ConfigBinder.RegisterOverloadInfo(overload, typeSpec, operation);
}
}
}
}
......@@ -34,9 +34,6 @@ private void RegisterMethodInvocation_OptionsBuilderExt(BinderInvocation invocat
return;
}
// We are going to emit calls to APIs on IServiceCollection.
_sourceGenSpec.TypeNamespaces.Add("Microsoft.Extensions.DependencyInjection");
if (targetMethod.Name is "Bind")
{
RegisterBindInvocation(invocation, typeSpec);
......@@ -61,20 +58,19 @@ private void RegisterBindInvocation(BinderInvocation invocation, TypeSpec typeSp
return;
}
if (paramCount is 2)
{
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T;
}
else if (paramCount is 3 && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
MethodsToGen_Extensions_OptionsBuilder overload = paramCount switch
{
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions;
}
else
2 => MethodsToGen_Extensions_OptionsBuilder.Bind_T,
3 when SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type) =>
MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions,
_ => MethodsToGen_Extensions_OptionsBuilder.None
};
if (overload is not MethodsToGen_Extensions_OptionsBuilder.None)
{
return;
RegisterAsInterceptor_OptionsBuilder(overload, operation);
RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec);
}
RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec);
}
private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeSpec typeSpec)
......@@ -85,12 +81,26 @@ private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeS
int paramCount = @params.Length;
Debug.Assert(paramCount >= 2);
if (paramCount is 3 && @params[1].Type.SpecialType is SpecialType.System_String && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
if (paramCount is 3 &&
@params[1].Type.SpecialType is SpecialType.System_String &&
SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
{
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions;
RegisterTypeForBindCoreUntypedGen(typeSpec);
RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation);
RegisterTypeForBindCoreMainGen(typeSpec);
}
}
private void RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation)
{
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= overload;
RegisterAsInterceptor(overload, operation);
// Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource.
_sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options");
// Emitting refs to OptionsBuilder<T>.
_sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection");
}
}
}
}
......@@ -79,12 +79,14 @@ private void RegisterMethodInvocation_ServiceCollectionExt(BinderInvocation invo
}
RegisterTypeForMethodGen(overload, typeSpec);
RegisterAsInterceptor(overload, operation);
}
private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec)
{
_sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload;
RegisterTypeForBindCoreUntypedGen(typeSpec);
_sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection");
RegisterTypeForBindCoreMainGen(typeSpec);
}
}
}
......
......@@ -11,6 +11,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion_LatestVS)" PrivateAssets="all" />
<!-- if MicrosoftCodeAnalysisVersion_LatestVS is still at 4.5.0 (eg: not source build) then update to a newer version. Remove this when we are able to update the value of MicrosoftCodeAnalysisVersion_LatestVS -->
<PackageReference Update="Microsoft.CodeAnalysis.CSharp.Workspaces" Condition="'$(MicrosoftCodeAnalysisVersion_LatestVS)' == '4.5.0'" Version="4.7.0-3.23314.3" />
</ItemGroup>
<ItemGroup>
......@@ -26,12 +28,14 @@
<Compile Include="ConfigurationBindingGenerator.cs" />
<Compile Include="ConfigurationBindingGenerator.Emitter.cs" />
<Compile Include="ConfigurationBindingGenerator.Parser.cs" />
<Compile Include="ConfigurationBindingGenerator.Suppressor.cs" />
<Compile Include="Helpers\Emitter\ConfigurationBinder.cs" />
<Compile Include="Helpers\Emitter\CoreBindingHelper.cs" />
<Compile Include="Helpers\Emitter\CoreBindingHelpers.cs" />
<Compile Include="Helpers\Emitter\ExceptionMessages.cs" />
<Compile Include="Helpers\Emitter\Helpers.cs" />
<Compile Include="Helpers\Emitter\OptionsBuilderConfigurationExtensions.cs" />
<Compile Include="Helpers\Emitter\OptionsConfigurationServiceCollectionExtensions.cs" />
<Compile Include="Helpers\InterceptorLocationInfo.cs" />
<Compile Include="Helpers\MethodsToGen.cs" />
<Compile Include="Helpers\Parser\BinderInvocation.cs" />
<Compile Include="Helpers\Parser\ConfigurationBinder.cs" />
......
......@@ -22,10 +22,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public List<ParameterSpec> ConstructorParameters { get; } = new();
private string _displayStringWithoutSpecialCharacters;
public string DisplayStringWithoutSpecialCharacters =>
_displayStringWithoutSpecialCharacters ??= $"{MinimalDisplayString.Replace(".", string.Empty).Replace("<", string.Empty).Replace(">", string.Empty)}";
public override bool NeedsMemberBinding => CanInitialize &&
Properties.Values.Count > 0 &&
Properties.Values.Any(p => p.ShouldBind());
......
......@@ -24,7 +24,7 @@ public string ParseMethodName
_parseMethodName ??= StringParsableTypeKind is StringParsableTypeKind.ByteArray
? "ParseByteArray"
// MinimalDisplayString.Length is certainly > 2.
: $"Parse{(char.ToUpper(MinimalDisplayString[0]) + MinimalDisplayString.Substring(1)).Replace(".", "")}";
: $"Parse{(char.ToUpper(DisplayString[0]) + DisplayString.Substring(1)).Replace(".", "")}";
return _parseMethodName;
}
......
// 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.Generic;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
internal sealed record SourceGenerationSpec
{
public Dictionary<Enum, List<InterceptorLocationInfo>> InterceptionInfo { get; } = new();
public ConfigurationBinderInterceptorInfo InterceptionInfo_ConfigBinder { get; } = new();
public Dictionary<MethodsToGen_CoreBindingHelper, HashSet<TypeSpec>> TypesForGen_CoreBindingHelper_Methods { get; } = new();
public Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> TypesForGen_ConfigurationBinder_BindMethods { get; } = new();
public HashSet<ParsableFromStringSpec> PrimitivesForHelperGen { get; } = new();
public HashSet<string> TypeNamespaces { get; } = new()
public HashSet<string> Namespaces { get; } = new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};
......
......@@ -17,17 +17,14 @@ public TypeSpec(ITypeSymbol type)
{
IsValueType = type.IsValueType;
Namespace = type.ContainingNamespace?.ToDisplayString();
FullyQualifiedDisplayString = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
MinimalDisplayString = type.ToDisplayString(s_minimalDisplayFormat);
Name = Namespace + "." + MinimalDisplayString.Replace(".", "+");
DisplayString = type.ToDisplayString(s_minimalDisplayFormat);
Name = Namespace + "." + DisplayString.Replace(".", "+");
IsInterface = type.TypeKind is TypeKind.Interface;
}
public string Name { get; }
public string FullyQualifiedDisplayString { get; }
public string MinimalDisplayString { get; }
public string DisplayString { get; }
public string? Namespace { get; }
......
......@@ -133,10 +133,10 @@
<value>The collection element type is not supported: '{0}'.</value>
</data>
<data name="Language VersionIsNotSupportedMessageFormat" xml:space="preserve">
<value>The project's language version has to be at least 'C# 11'.</value>
<value>The project's language version has to be at least 'C# 12'.</value>
</data>
<data name="LanguageVersionIsNotSupportedTitle" xml:space="preserve">
<value>Language version is required to be at least C# 11</value>
<value>Language version is required to be at least C# 12</value>
</data>
<data name="MissingPublicInstanceConstructor" xml:space="preserve">
<value>Cannot create instance of type '{0}' because it is missing a public instance constructor.</value>
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">Jazyková verze projektu musí být alespoň C# 11</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">Jazyková verze projektu musí být alespoň C# 11</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">Verze jazyka musí být alespoň C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">Verze jazyka musí být alespoň C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">Die Sprachversion des Projekts muss mindestens „C# 11“ sein</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">Die Sprachversion des Projekts muss mindestens „C# 11“ sein</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">Die Sprachversion muss mindestens C# 11 sein</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">Die Sprachversion muss mindestens C# 11 sein</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">La versión del lenguaje del proyecto debe ser al menos "C# 11".</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">La versión del lenguaje del proyecto debe ser al menos "C# 11".</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">La versión del lenguaje debe ser al menos C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">La versión del lenguaje debe ser al menos C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">La version de langage du projet doit être au moins « C# 11 ».</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">La version de langage du projet doit être au moins « C# 11 ».</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">La version du langage doit être au moins C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">La version du langage doit être au moins C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">La versione del linguaggio del progetto deve essere almeno 'C# 11'.</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">La versione del linguaggio del progetto deve essere almeno 'C# 11'.</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">La versione del linguaggio deve essere almeno C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">La versione del linguaggio deve essere almeno C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">言語バージョンは少なくとも C# 11 である必要があります</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">言語バージョンは少なくとも C# 11 である必要があります</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다.</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다.</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">언어 버전은 C# 11 이상이어야 합니다.</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">언어 버전은 C# 11 이상이어야 합니다.</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">Wersja językowa projektu musi mieć wartość co najmniej „C# 11”.</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">Wersja językowa projektu musi mieć wartość co najmniej „C# 11”.</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">Wymagana jest wersja językowa co najmniej C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">Wymagana jest wersja językowa co najmniej C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">A versão do idioma do projeto deve ser no mínimo 'C# 11'.</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">A versão do idioma do projeto deve ser no mínimo 'C# 11'.</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">A versão do idioma deve ser pelo menos C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">A versão do idioma deve ser pelo menos C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">Версия языка проекта должна быть не ниже "C# 11".</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">Версия языка проекта должна быть не ниже "C# 11".</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">Версия языка должна быть не ниже C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">Версия языка должна быть не ниже C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">Projenin dil sürümü en az 'C# 11' olmalıdır.</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">Projenin dil sürümü en az 'C# 11' olmalıdır.</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">Dil sürümünün en az C# 11 olması gerekir</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">Dil sürümünün en az C# 11 olması gerekir</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">项目的语言版本必须至少为 "C# 11"。</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">项目的语言版本必须至少为 "C# 11"。</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">语言版本必须至少为 C# 11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">语言版本必须至少为 C# 11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -28,13 +28,13 @@
<note />
</trans-unit>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="translated">專案的語言版本必須至少為 'C# 11'。</target>
<source>The project's language version has to be at least 'C# 12'.</source>
<target state="needs-review-translation">專案的語言版本必須至少為 'C# 11'。</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="translated">語言版本要求至少為 C#11</target>
<source>Language version is required to be at least C# 12</source>
<target state="needs-review-translation">語言版本要求至少為 C#11</target>
<note />
</trans-unit>
<trans-unit id="MissingPublicInstanceConstructor">
......
......@@ -8,7 +8,6 @@
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
#if BUILDING_SOURCE_GENERATOR_TESTS
using Microsoft.Extensions.Configuration;
#endif
......@@ -2037,6 +2036,7 @@ public void ComplexObj_As_Enumerable_Element()
ValidateGeolocation(obj);
}
#if !BUILDING_SOURCE_GENERATOR_TESTS
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
public void TraceSwitchTest()
{
......@@ -2056,6 +2056,7 @@ public void TraceSwitchTest()
Assert.Equal("Info", ts.Value);
#endif // NETCOREAPP
}
#endif
private void ValidateGeolocation(IGeolocation location)
{
......
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -18,11 +25,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 12, 17)]
public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" });
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
......@@ -46,16 +60,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return obj;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<string, int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -67,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)
......@@ -83,11 +87,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -99,11 +98,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref ICollection<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -115,11 +109,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref IReadOnlyList<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (obj is not ICollection<int> temp)
{
return;
......@@ -136,11 +125,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, int> 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,11 +136,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref IDictionary<string, int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -168,11 +147,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary<string, int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (obj is not IDictionary<string, int> temp)
{
return;
......@@ -189,11 +163,6 @@ 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 section1)
......@@ -229,6 +198,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -281,7 +251,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -298,5 +268,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,18 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null);
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions));
using System;
using System.CodeDom.Compiler;
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null);
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -23,20 +24,72 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
#region IConfiguration extensions.
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 13, 18)]
public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var typedObj = (Program.MyClass)obj;
BindCore(configuration, ref typedObj, binderOptions: null);
}
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 14, 24)]
public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var typedObj = (Program.MyClass)obj;
BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions));
}
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var typedObj = (Program.MyClass)obj;
BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null);
}
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
{
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -48,11 +101,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -64,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> 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))
......@@ -81,11 +124,6 @@ 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"]!;
......@@ -120,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -163,7 +202,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -180,5 +219,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null);
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
#region IConfiguration extensions.
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var typedObj = (Program.MyClass)obj;
BindCore(configuration, ref typedObj, binderOptions: null);
}
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
{
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> 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))
......@@ -75,11 +88,6 @@ 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"]!;
......@@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions));
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
#region IConfiguration extensions.
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var typedObj = (Program.MyClass)obj;
BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions));
}
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
{
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> 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))
......@@ -75,11 +88,6 @@ 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"]!;
......@@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -157,7 +166,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -174,5 +183,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null);
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
#region IConfiguration extensions.
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var typedObj = (Program.MyClass)obj;
BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null);
}
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
{
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> 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))
......@@ -75,11 +88,6 @@ 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"]!;
......@@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,21 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T));
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null);
using System;
using System.CodeDom.Compiler;
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions);
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -26,11 +24,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 12, 38)]
public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 14, 36)]
public static T? Get<T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T));
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 13, 36)]
public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null);
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 15, 36)]
public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions) => GetCore(configuration, type, configureOptions);
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
......@@ -54,24 +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 global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -83,11 +94,6 @@ 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 temp2 = new List<int>();
BindCore(configuration, ref temp2, binderOptions);
int originalCount = obj.Length;
......@@ -97,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -113,11 +114,6 @@ 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"]!;
......@@ -154,11 +150,6 @@ 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 value15)
......@@ -167,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -219,7 +211,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -236,5 +228,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,21 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T));
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key);
using System;
using System.CodeDom.Compiler;
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -25,11 +23,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System;
using System.CodeDom.Compiler;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 13, 18)]
public static T? GetValue<T>(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T));
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 16, 24)]
public static T? GetValue<T>(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 14, 24)]
public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key);
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 17, 24)]
public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue;
#endregion IConfiguration extensions.
#region Core binding extensions.
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
{
if (configuration is null)
......@@ -48,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);
}
......@@ -114,5 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T));
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System;
using System.CodeDom.Compiler;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 10, 20)]
public static T? GetValue<T>(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T));
#endregion IConfiguration extensions.
#region Core binding extensions.
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
{
if (configuration is null)
......@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static T? GetValue<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System;
using System.CodeDom.Compiler;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
public static T? GetValue<T>(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
#endregion IConfiguration extensions.
#region Core binding extensions.
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
{
if (configuration is null)
......@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key);
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System;
using System.CodeDom.Compiler;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 10, 20)]
public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key);
#endregion IConfiguration extensions.
#region Core binding extensions.
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
{
if (configuration is null)
......@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue;
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System;
using System.CodeDom.Compiler;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 11, 20)]
public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue;
#endregion IConfiguration extensions.
#region Core binding extensions.
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
{
if (configuration is null)
......@@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
......@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return obj;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -66,11 +75,6 @@ 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 temp1 = new List<int>();
BindCore(configuration, ref temp1, binderOptions);
int originalCount = obj.Length;
......@@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -96,11 +95,6 @@ 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"]!;
......@@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T));
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
public static T? Get<T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T));
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
......@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return obj;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -66,11 +75,6 @@ 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 temp1 = new List<int>();
BindCore(configuration, ref temp1, binderOptions);
int originalCount = obj.Length;
......@@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -96,11 +95,6 @@ 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"]!;
......@@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null);
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null);
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
......@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return obj;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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 value1)
......@@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions);
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IConfiguration extensions.
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 11, 20)]
public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions) => GetCore(configuration, type, configureOptions);
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
......@@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return obj;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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 value1)
......@@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,31 +2,18 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedOptionsBuilderBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Registers the dependency injection container to bind <typeparamref name="TOptions"/> against the <see cref="global::Microsoft.Extensions.Configuration.IConfiguration"/> obtained from the DI service provider.</summary>
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> BindConfiguration<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, string configSectionPath, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions = null) where TOptions : class
{
if (optionsBuilder is null)
{
throw new global::System.ArgumentNullException(nameof(optionsBuilder));
}
using System;
using System.CodeDom.Compiler;
if (configSectionPath is null)
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
throw new global::System.ArgumentNullException(nameof(configSectionPath));
}
optionsBuilder.Configure<global::Microsoft.Extensions.Configuration.IConfiguration>((obj, configuration) =>
{
global::Microsoft.Extensions.Configuration.IConfiguration section = string.Equals(string.Empty, configSectionPath, global::System.StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath);
global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(section, obj, typeof(TOptions), configureOptions);
});
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>, global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>>(optionsBuilder.Services);
return optionsBuilder;
}
}
......@@ -34,31 +21,74 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region OptionsBuilder<TOptions> extensions.
/// <summary>Registers the dependency injection container to bind <typeparamref name="TOptions"/> against the <see cref="IConfiguration"/> obtained from the DI service provider.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 12, 24)]
public static OptionsBuilder<TOptions> BindConfiguration<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, string configSectionPath, Action<BinderOptions>? configureOptions = null) where TOptions : class
{
if (optionsBuilder is null)
{
throw new ArgumentNullException(nameof(optionsBuilder));
}
if (configSectionPath is null)
{
throw new ArgumentNullException(nameof(configSectionPath));
}
optionsBuilder.Configure<IConfiguration>((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, typeof(TOptions), configureOptions);
});
optionsBuilder.Services.AddSingleton<IOptionsChangeTokenSource<TOptions>, ConfigurationChangeTokenSource<TOptions>>();
return optionsBuilder;
}
#endregion OptionsBuilder<TOptions> extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (!HasValueOrChildren(configuration))
{
return;
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (type == typeof(Program.MyClass))
{
var temp = (Program.MyClass)obj;
......@@ -66,16 +96,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -87,11 +112,6 @@ 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"]!;
......@@ -110,6 +130,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -162,7 +183,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -179,5 +200,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,49 +2,18 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedOptionsBuilderBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
{
return global::GeneratedOptionsBuilderBinder.Bind(optionsBuilder, configuration, configureOptions: null);
}
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
{
if (optionsBuilder is null)
{
throw new global::System.ArgumentNullException(nameof(optionsBuilder));
}
global::GeneratedServiceCollectionBinder.Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
return optionsBuilder;
}
}
using System;
using System.CodeDom.Compiler;
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedServiceCollectionBinder
{
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
if (services is null)
{
throw new global::System.ArgumentNullException(nameof(services));
}
if (configuration is null)
public InterceptsLocationAttribute(string filePath, int line, int column)
{
throw new global::System.ArgumentNullException(nameof(configuration));
}
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
}
}
......@@ -52,31 +21,79 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region OptionsBuilder<TOptions> extensions.
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration) where TOptions : class
{
return Bind(optionsBuilder, configuration, configureOptions: null);
}
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
if (optionsBuilder is null)
{
throw new ArgumentNullException(nameof(optionsBuilder));
}
Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
return optionsBuilder;
}
#endregion OptionsBuilder<TOptions> extensions.
#region IServiceCollection extensions.
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
OptionsServiceCollectionExtensions.AddOptions(services);
services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
}
#endregion IServiceCollection extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (!HasValueOrChildren(configuration))
{
return;
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (type == typeof(Program.MyClass))
{
var temp = (Program.MyClass)obj;
......@@ -84,16 +101,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -105,11 +117,6 @@ 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"]!;
......@@ -128,6 +135,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -180,7 +188,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -197,5 +205,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,43 +2,18 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedOptionsBuilderBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
{
if (optionsBuilder is null)
{
throw new global::System.ArgumentNullException(nameof(optionsBuilder));
}
global::GeneratedServiceCollectionBinder.Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
return optionsBuilder;
}
}
using System;
using System.CodeDom.Compiler;
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedServiceCollectionBinder
{
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
if (services is null)
{
throw new global::System.ArgumentNullException(nameof(services));
}
if (configuration is null)
public InterceptsLocationAttribute(string filePath, int line, int column)
{
throw new global::System.ArgumentNullException(nameof(configuration));
}
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
}
}
......@@ -46,31 +21,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region OptionsBuilder<TOptions> extensions.
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
if (optionsBuilder is null)
{
throw new ArgumentNullException(nameof(optionsBuilder));
}
Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
return optionsBuilder;
}
#endregion OptionsBuilder<TOptions> extensions.
#region IServiceCollection extensions.
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
OptionsServiceCollectionExtensions.AddOptions(services);
services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
}
#endregion IServiceCollection extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (!HasValueOrChildren(configuration))
{
return;
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (type == typeof(Program.MyClass))
{
var temp = (Program.MyClass)obj;
......@@ -78,16 +95,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -99,11 +111,6 @@ 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"]!;
......@@ -122,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -174,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -191,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,12 +2,19 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedConfigurationBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null);
using System;
using System.CodeDom.Compiler;
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int column)
{
}
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
......@@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(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)
#region IConfiguration extensions.
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 13, 16)]
public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
var typedObj = (Program.MyClass)obj;
BindCore(configuration, ref typedObj, binderOptions: null);
}
#endregion IConfiguration extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(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)
{
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
if (configuration["Prop0"] is string value0)
......@@ -168,6 +191,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -517,5 +541,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,64 +2,84 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedServiceCollectionBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
{
return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, string.Empty, configuration, configureOptions: null);
}
using System;
using System.CodeDom.Compiler;
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
if (services is null)
{
throw new global::System.ArgumentNullException(nameof(services));
}
if (configuration is null)
public InterceptsLocationAttribute(string filePath, int line, int column)
{
throw new global::System.ArgumentNullException(nameof(configuration));
}
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IServiceCollection extensions.
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration) where TOptions : class
{
return Configure<TOptions>(services, string.Empty, configuration, configureOptions: null);
}
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
OptionsServiceCollectionExtensions.AddOptions(services);
services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
}
#endregion IServiceCollection extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (!HasValueOrChildren(configuration))
{
return;
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (type == typeof(Program.MyClass))
{
var temp = (Program.MyClass)obj;
......@@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -88,11 +103,6 @@ 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 value1)
......@@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
var value = new Program.MyClass2();
......@@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -134,11 +134,6 @@ 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"]!;
......@@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,64 +2,84 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedServiceCollectionBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
{
return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, string.Empty, configuration, configureOptions);
}
using System;
using System.CodeDom.Compiler;
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
if (services is null)
{
throw new global::System.ArgumentNullException(nameof(services));
}
if (configuration is null)
public InterceptsLocationAttribute(string filePath, int line, int column)
{
throw new global::System.ArgumentNullException(nameof(configuration));
}
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IServiceCollection extensions.
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
return Configure<TOptions>(services, string.Empty, configuration, configureOptions);
}
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
OptionsServiceCollectionExtensions.AddOptions(services);
services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
}
#endregion IServiceCollection extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (!HasValueOrChildren(configuration))
{
return;
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (type == typeof(Program.MyClass))
{
var temp = (Program.MyClass)obj;
......@@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -88,11 +103,6 @@ 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 value1)
......@@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
var value = new Program.MyClass2();
......@@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -134,11 +134,6 @@ 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"]!;
......@@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -2,64 +2,84 @@
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
internal static class GeneratedServiceCollectionBinder
namespace System.Runtime.CompilerServices
{
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
{
return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, name, configuration, configureOptions: null);
}
using System;
using System.CodeDom.Compiler;
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : Attribute
{
if (services is null)
{
throw new global::System.ArgumentNullException(nameof(services));
}
if (configuration is null)
public InterceptsLocationAttribute(string filePath, int line, int column)
{
throw new global::System.ArgumentNullException(nameof(configuration));
}
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);
global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
}
}
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
/// <summary>Provide core binding logic.</summary>
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
file static class CoreBindingHelper
file static class BindingExtensions
{
#region IServiceCollection extensions.
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
[InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration) where TOptions : class
{
return Configure<TOptions>(services, name, configuration, configureOptions: null);
}
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
OptionsServiceCollectionExtensions.AddOptions(services);
services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
}
#endregion IServiceCollection extensions.
#region Core binding extensions.
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (!HasValueOrChildren(configuration))
{
return;
}
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
if (type == typeof(Program.MyClass))
{
var temp = (Program.MyClass)obj;
......@@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
return;
}
throw new global::System.NotSupportedException($"Unable to bind to type '{type}': 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<int> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -88,11 +103,6 @@ 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 value1)
......@@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
var value = new Program.MyClass2();
......@@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (section.Value is string value)
......@@ -134,11 +134,6 @@ 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"]!;
......@@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
}
}
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
{
......@@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
return binderOptions;
......@@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
}
}
#endregion Core binding extensions.
}
}
......@@ -8,6 +8,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
{
public partial class ConfigurationBindingGeneratorTests
{
#region IServiceCollection extensions.
private string GetConfigureSource(string paramList) => $$"""
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
......@@ -40,7 +41,9 @@ public class MyClass2
}
}
""";
#endregion IServiceCollection extensions.
#region OptionsBuilder<T> extensions.
[Fact]
public async Task Configure_T() =>
await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection);
......@@ -126,5 +129,6 @@ public class MyClass
await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(), extType: ExtensionClassType.OptionsBuilder);
await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(@", _ => { }"), extType: ExtensionClassType.OptionsBuilder);
}
#endregion OptionsBuilder<T> extensions.
}
}
......@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
......@@ -44,7 +43,6 @@ public class MyClass2 { }
[Theory]
[InlineData(LanguageVersion.Preview)]
[InlineData(LanguageVersion.CSharp11)]
public async Task Bind(LanguageVersion langVersion) =>
await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder);
......@@ -651,7 +649,7 @@ public interface ICustomSet<T> : ISet<T>
await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) =>
{
Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count() , d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()));
Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count(), d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()));
Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count());
Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count());
});
......
......@@ -4,7 +4,7 @@
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<!-- Type not supported; property on type not suppported -->
<NoWarn>SYSLIB1100,SYSLIB1101</NoWarn>
<!-- The SDK disables the configuration binding generator by default no matter how it was referenced, so we need to enable it here for testing. -->
<Features>$(Features);InterceptorsPreview</Features>
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
</PropertyGroup>
......
......@@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
<EnableDefaultItems>true</EnableDefaultItems>
<Features>$(Features);InterceptorsPreview</Features>
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
<IsPackable>true</IsPackable>
<PackageDescription>Configuration support for Microsoft.Extensions.Logging.</PackageDescription>
......
......@@ -7,7 +7,9 @@
<DefineConstants>$(DefineConstants);NO_SUPPRESS_GC_TRANSITION</DefineConstants>
<IncludePlatformAttributes>true</IncludePlatformAttributes>
<IsPackable>true</IsPackable>
<Features>$(Features);InterceptorsPreview</Features>
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<PackageDescription>Console logger provider implementation for Microsoft.Extensions.Logging.</PackageDescription>
</PropertyGroup>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册