1- using System . Reflection ;
1+ using System . Collections . Generic ;
2+ using System . Reflection ;
23using System . Runtime . Serialization ;
34
45namespace System . Text . Json . Serialization
@@ -8,15 +9,13 @@ namespace System.Text.Json.Serialization
89 /// </summary>
910 public class JsonStringEnumMemberConverter : JsonConverterFactory
1011 {
11- private readonly JsonNamingPolicy ? _NamingPolicy ;
12- private readonly bool _AllowIntegerValues ;
13- private readonly ulong ? _DeserializationFailureFallbackValue ;
12+ private readonly HashSet < Type > ? _EnumTypes ;
13+ private readonly JsonStringEnumMemberConverterOptions ? _Options ;
1414
1515 /// <summary>
1616 /// Initializes a new instance of the <see cref="JsonStringEnumMemberConverter"/> class.
1717 /// </summary>
1818 public JsonStringEnumMemberConverter ( )
19- : this ( namingPolicy : null , allowIntegerValues : true )
2019 {
2120 }
2221
@@ -30,46 +29,91 @@ public JsonStringEnumMemberConverter()
3029 /// True to allow undefined enum values. When true, if an enum value isn't
3130 /// defined it will output as a number rather than a string.
3231 /// </param>
33- /// <param name="deserializationFailureFallbackValue">
34- /// Optional default value to use when a json string does not match
35- /// anything defined on the target enum. If not specified a <see
36- /// cref="JsonException"/> is thrown for all failures.
37- /// </param>
38- public JsonStringEnumMemberConverter ( JsonNamingPolicy ? namingPolicy = null , bool allowIntegerValues = true , ulong ? deserializationFailureFallbackValue = null )
32+ public JsonStringEnumMemberConverter ( JsonNamingPolicy ? namingPolicy = null , bool allowIntegerValues = true )
33+ : this ( new JsonStringEnumMemberConverterOptions { NamingPolicy = namingPolicy , AllowIntegerValues = allowIntegerValues } )
3934 {
40- _NamingPolicy = namingPolicy ;
41- _AllowIntegerValues = allowIntegerValues ;
42- _DeserializationFailureFallbackValue = deserializationFailureFallbackValue ;
4335 }
4436
37+ /// <summary>
38+ /// Initializes a new instance of the <see cref="JsonStringEnumMemberConverter"/> class.
39+ /// </summary>
40+ /// <param name="options"><see cref="JsonStringEnumMemberConverterOptions"/>.</param>
41+ /// <param name="targetEnumTypes">Optional list of supported enum types to be converted. Specify <see langword="null"/> or empty to convert all enums.</param>
42+ public JsonStringEnumMemberConverter ( JsonStringEnumMemberConverterOptions options , params Type [ ] targetEnumTypes )
43+ {
44+ _Options = options ?? throw new ArgumentNullException ( nameof ( options ) ) ;
45+
46+ if ( targetEnumTypes != null && targetEnumTypes . Length > 0 )
47+ {
48+ #if NETSTANDARD2_0
49+ _EnumTypes = new HashSet < Type > ( ) ;
50+ #else
51+ _EnumTypes = new HashSet < Type > ( targetEnumTypes . Length ) ;
52+ #endif
53+ foreach ( Type enumType in targetEnumTypes )
54+ {
55+ if ( enumType . IsEnum )
56+ {
57+ _EnumTypes . Add ( enumType ) ;
58+ _EnumTypes . Add ( typeof ( Nullable < > ) . MakeGenericType ( enumType ) ) ;
59+ continue ;
60+ }
61+
62+ if ( enumType . IsGenericType )
63+ {
64+ ( bool IsNullableEnum , Type ? UnderlyingType ) = TestNullableEnum ( enumType ) ;
65+ if ( IsNullableEnum )
66+ {
67+ _EnumTypes . Add ( UnderlyingType ! ) ;
68+ _EnumTypes . Add ( enumType ) ;
69+ continue ;
70+ }
71+ }
72+
73+ throw new NotSupportedException ( $ "Type { enumType } is not supported by JsonStringEnumMemberConverter. Only enum types can be converted.") ;
74+ }
75+ }
76+ }
77+
78+ #pragma warning disable CA1062 // Validate arguments of public methods
4579 /// <inheritdoc/>
4680 public override bool CanConvert ( Type typeToConvert )
4781 {
4882 // Don't perform a typeToConvert == null check for performance. Trust our callers will be nice.
49- #pragma warning disable CA1062 // Validate arguments of public methods
50- return typeToConvert . IsEnum
83+ return _EnumTypes != null
84+ ? _EnumTypes . Contains ( typeToConvert )
85+ : typeToConvert . IsEnum
5186 || ( typeToConvert . IsGenericType && TestNullableEnum ( typeToConvert ) . IsNullableEnum ) ;
52- #pragma warning restore CA1062 // Validate arguments of public methods
5387 }
88+ #pragma warning restore CA1062 // Validate arguments of public methods
5489
5590 /// <inheritdoc/>
5691 public override JsonConverter CreateConverter ( Type typeToConvert , JsonSerializerOptions options )
5792 {
5893 ( bool IsNullableEnum , Type ? UnderlyingType ) = TestNullableEnum ( typeToConvert ) ;
5994
60- return IsNullableEnum
61- ? ( JsonConverter ) Activator . CreateInstance (
62- typeof ( NullableEnumMemberConverter < > ) . MakeGenericType ( UnderlyingType ) ,
63- BindingFlags . Instance | BindingFlags . Public ,
64- binder : null ,
65- args : new object ? [ ] { _NamingPolicy , _AllowIntegerValues , _DeserializationFailureFallbackValue } ,
66- culture : null )
67- : ( JsonConverter ) Activator . CreateInstance (
68- typeof ( EnumMemberConverter < > ) . MakeGenericType ( typeToConvert ) ,
69- BindingFlags . Instance | BindingFlags . Public ,
70- binder : null ,
71- args : new object ? [ ] { _NamingPolicy , _AllowIntegerValues , _DeserializationFailureFallbackValue } ,
72- culture : null ) ;
95+ try
96+ {
97+ return IsNullableEnum
98+ ? ( JsonConverter ) Activator . CreateInstance (
99+ typeof ( NullableEnumMemberConverter < > ) . MakeGenericType ( UnderlyingType ) ,
100+ BindingFlags . Instance | BindingFlags . Public ,
101+ binder : null ,
102+ args : new object ? [ ] { _Options } ,
103+ culture : null )
104+ : ( JsonConverter ) Activator . CreateInstance (
105+ typeof ( EnumMemberConverter < > ) . MakeGenericType ( typeToConvert ) ,
106+ BindingFlags . Instance | BindingFlags . Public ,
107+ binder : null ,
108+ args : new object ? [ ] { _Options } ,
109+ culture : null ) ;
110+ }
111+ catch ( TargetInvocationException targetInvocationEx )
112+ {
113+ if ( targetInvocationEx . InnerException != null )
114+ throw targetInvocationEx . InnerException ;
115+ throw ;
116+ }
73117 }
74118
75119 private static ( bool IsNullableEnum , Type ? UnderlyingType ) TestNullableEnum ( Type typeToConvert )
@@ -79,16 +123,32 @@ private static (bool IsNullableEnum, Type? UnderlyingType) TestNullableEnum(Type
79123 return ( UnderlyingType ? . IsEnum ?? false , UnderlyingType ) ;
80124 }
81125
126+ internal static ulong GetEnumValue ( TypeCode enumTypeCode , object value )
127+ {
128+ return enumTypeCode switch
129+ {
130+ TypeCode . Int32 => ( ulong ) ( int ) value ,
131+ TypeCode . Int64 => ( ulong ) ( long ) value ,
132+ TypeCode . Int16 => ( ulong ) ( short ) value ,
133+ TypeCode . Byte => ( byte ) value ,
134+ TypeCode . UInt32 => ( uint ) value ,
135+ TypeCode . UInt64 => ( ulong ) value ,
136+ TypeCode . UInt16 => ( ushort ) value ,
137+ TypeCode . SByte => ( ulong ) ( sbyte ) value ,
138+ _ => throw new NotSupportedException ( $ "Enum '{ value } ' of { enumTypeCode } type is not supported.") ,
139+ } ;
140+ }
141+
82142#pragma warning disable CA1812 // Remove class never instantiated
83143 private class EnumMemberConverter < TEnum > : JsonConverter < TEnum >
84144 where TEnum : struct , Enum
85145#pragma warning restore CA1812 // Remove class never instantiated
86146 {
87147 private readonly JsonStringEnumMemberConverterHelper < TEnum > _JsonStringEnumMemberConverterHelper ;
88148
89- public EnumMemberConverter ( JsonNamingPolicy ? namingPolicy , bool allowIntegerValues , ulong ? deserializationFailureFallbackValue )
149+ public EnumMemberConverter ( JsonStringEnumMemberConverterOptions ? options )
90150 {
91- _JsonStringEnumMemberConverterHelper = new JsonStringEnumMemberConverterHelper < TEnum > ( namingPolicy , allowIntegerValues , deserializationFailureFallbackValue ) ;
151+ _JsonStringEnumMemberConverterHelper = new JsonStringEnumMemberConverterHelper < TEnum > ( options ) ;
92152 }
93153
94154 public override TEnum Read ( ref Utf8JsonReader reader , Type typeToConvert , JsonSerializerOptions options )
@@ -105,9 +165,9 @@ private class NullableEnumMemberConverter<TEnum> : JsonConverter<TEnum?>
105165 {
106166 private readonly JsonStringEnumMemberConverterHelper < TEnum > _JsonStringEnumMemberConverterHelper ;
107167
108- public NullableEnumMemberConverter ( JsonNamingPolicy ? namingPolicy , bool allowIntegerValues , ulong ? deserializationFailureFallbackValue )
168+ public NullableEnumMemberConverter ( JsonStringEnumMemberConverterOptions ? options )
109169 {
110- _JsonStringEnumMemberConverterHelper = new JsonStringEnumMemberConverterHelper < TEnum > ( namingPolicy , allowIntegerValues , deserializationFailureFallbackValue ) ;
170+ _JsonStringEnumMemberConverterHelper = new JsonStringEnumMemberConverterHelper < TEnum > ( options ) ;
111171 }
112172
113173 public override TEnum ? Read ( ref Utf8JsonReader reader , Type typeToConvert , JsonSerializerOptions options )
0 commit comments