Skip to content

Commit 086ac0a

Browse files
authored
Improve enum parsing in config binder generator (#89823)
1 parent 3bba4f2 commit 086ac0a

File tree

3 files changed

+52
-9
lines changed

3 files changed

+52
-9
lines changed

src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ private void EmitBindLogicFromString(
124124
{
125125
parsedValueExpr = stringValueToParse_Expr;
126126
}
127+
else if (typeKind is StringParsableTypeKind.Enum)
128+
{
129+
parsedValueExpr = $"ParseEnum<{type.MinimalDisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
130+
}
127131
else
128132
{
129133
string helperMethodDisplayString = GetHelperMethodDisplayString(type.ParseMethodName);

src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -429,10 +429,24 @@ private void EmitHelperMethods()
429429
_emitBlankLineBeforeNextStatement = true;
430430
}
431431

432+
bool enumTypeExists = false;
433+
432434
foreach (ParsableFromStringSpec type in _sourceGenSpec.PrimitivesForHelperGen)
433435
{
434436
EmitBlankLineIfRequired();
435-
EmitPrimitiveParseMethod(type);
437+
438+
if (type.StringParsableTypeKind == StringParsableTypeKind.Enum)
439+
{
440+
if (!enumTypeExists)
441+
{
442+
EmitEnumParseMethod();
443+
enumTypeExists = true;
444+
}
445+
}
446+
else
447+
{
448+
EmitPrimitiveParseMethod(type);
449+
}
436450
}
437451
}
438452

@@ -518,6 +532,30 @@ private void EmitGetBinderOptionsHelper()
518532
""");
519533
}
520534

535+
private void EmitEnumParseMethod()
536+
{
537+
string innerExceptionTypeDisplayString = _useFullyQualifiedNames ? "global::System.Exception" : "Exception";
538+
string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof(T)}}");
539+
540+
_writer.WriteLine($$"""
541+
public static T ParseEnum<T>(string value, Func<string?> getPath) where T : struct
542+
{
543+
try
544+
{
545+
#if NETFRAMEWORK || NETSTANDARD2_0
546+
return (T)Enum.Parse(typeof(T), value, ignoreCase: true);
547+
#else
548+
return Enum.Parse<T>(value, ignoreCase: true);
549+
#endif
550+
}
551+
catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}})
552+
{
553+
throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}});
554+
}
555+
}
556+
""");
557+
}
558+
521559
private void EmitPrimitiveParseMethod(ParsableFromStringSpec type)
522560
{
523561
string innerExceptionTypeDisplayString;
@@ -546,10 +584,7 @@ private void EmitPrimitiveParseMethod(ParsableFromStringSpec type)
546584
switch (typeKind)
547585
{
548586
case StringParsableTypeKind.Enum:
549-
{
550-
parsedValueExpr = $"({typeDisplayString}){Identifier.Enum}.{Identifier.Parse}(typeof({typeDisplayString}), {Identifier.value}, ignoreCase: true)";
551-
}
552-
break;
587+
return;
553588
case StringParsableTypeKind.ByteArray:
554589
{
555590
parsedValueExpr = $"Convert.FromBase64String({Identifier.value})";

src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
139139

140140
if (configuration["Prop27"] is string value22)
141141
{
142-
obj.Prop27 = ParseDayOfWeek(value22, () => configuration.GetSection("Prop27").Path);
142+
obj.Prop27 = ParseEnum<DayOfWeek>(value22, () => configuration.GetSection("Prop27").Path);
143143
}
144144

145145
if (configuration["Prop7"] is string value23)
@@ -430,15 +430,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
430430
}
431431
}
432432

433-
public static DayOfWeek ParseDayOfWeek(string value, Func<string?> getPath)
433+
public static T ParseEnum<T>(string value, Func<string?> getPath) where T : struct
434434
{
435435
try
436436
{
437-
return (DayOfWeek)Enum.Parse(typeof(DayOfWeek), value, ignoreCase: true);
437+
#if NETFRAMEWORK || NETSTANDARD2_0
438+
return (T)Enum.Parse(typeof(T), value, ignoreCase: true);
439+
#else
440+
return Enum.Parse<T>(value, ignoreCase: true);
441+
#endif
438442
}
439443
catch (Exception exception)
440444
{
441-
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DayOfWeek)}'.", exception);
445+
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(T)}'.", exception);
442446
}
443447
}
444448

0 commit comments

Comments
 (0)