@@ -27,6 +27,7 @@ public EnumInfo(string name, TEnum enumValue, ulong rawValue)
2727 }
2828
2929 private const BindingFlags EnumBindings = BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . Static ;
30+ private const int MaximumAutoGrowthCacheSize = 64 ;
3031
3132#if NETSTANDARD2_0
3233 private static readonly string [ ] s_Split = new string [ ] { ", " } ;
@@ -38,8 +39,10 @@ public EnumInfo(string name, TEnum enumValue, ulong rawValue)
3839 private readonly Type _EnumType ;
3940 private readonly TypeCode _EnumTypeCode ;
4041 private readonly bool _IsFlags ;
41- private readonly Dictionary < TEnum , EnumInfo > _RawToTransformed ;
42- private readonly Dictionary < string , EnumInfo > _TransformedToRaw ;
42+ private readonly object _TransformedToRawCopyLockObject = new ( ) ;
43+ private readonly object _RawToTransformedCopyLockObject = new ( ) ;
44+ private Dictionary < TEnum , EnumInfo > _RawToTransformed ;
45+ private Dictionary < string , EnumInfo > _TransformedToRaw ;
4346
4447 public JsonStringEnumMemberConverterHelper ( JsonStringEnumMemberConverterOptions ? options )
4548 {
@@ -58,10 +61,12 @@ public JsonStringEnumMemberConverterHelper(JsonStringEnumMemberConverterOptions?
5861 string [ ] builtInNames = _EnumType . GetEnumNames ( ) ;
5962 Array builtInValues = _EnumType . GetEnumValues ( ) ;
6063
61- _RawToTransformed = new Dictionary < TEnum , EnumInfo > ( ) ;
62- _TransformedToRaw = new Dictionary < string , EnumInfo > ( ) ;
64+ int numberOfBuiltInNames = builtInNames . Length ;
6365
64- for ( int i = 0 ; i < builtInNames . Length ; i ++ )
66+ _RawToTransformed = new Dictionary < TEnum , EnumInfo > ( numberOfBuiltInNames ) ;
67+ _TransformedToRaw = new Dictionary < string , EnumInfo > ( numberOfBuiltInNames ) ;
68+
69+ for ( int i = 0 ; i < numberOfBuiltInNames ; i ++ )
6570 {
6671 Enum ? enumValue = ( Enum ? ) builtInValues . GetValue ( i ) ;
6772 if ( enumValue == null )
@@ -101,8 +106,10 @@ public TEnum Read(ref Utf8JsonReader reader)
101106 {
102107 string enumString = reader . GetString ( ) ! ;
103108
109+ Dictionary < string , EnumInfo > transformedToRaw = _TransformedToRaw ;
110+
104111 // Case sensitive search attempted first.
105- if ( _TransformedToRaw . TryGetValue ( enumString , out EnumInfo ? enumInfo ) )
112+ if ( transformedToRaw . TryGetValue ( enumString , out EnumInfo ? enumInfo ) )
106113 return enumInfo . EnumValue ;
107114
108115 if ( _IsFlags )
@@ -117,15 +124,15 @@ public TEnum Read(ref Utf8JsonReader reader)
117124 foreach ( string flagValue in flagValues )
118125 {
119126 // Case sensitive search attempted first.
120- if ( _TransformedToRaw . TryGetValue ( flagValue , out enumInfo ) )
127+ if ( transformedToRaw . TryGetValue ( flagValue , out enumInfo ) )
121128 {
122129 calculatedValue |= enumInfo . RawValue ;
123130 }
124131 else
125132 {
126133 // Case insensitive search attempted second.
127134 bool matched = false ;
128- foreach ( KeyValuePair < string , EnumInfo > enumItem in _TransformedToRaw )
135+ foreach ( KeyValuePair < string , EnumInfo > enumItem in transformedToRaw )
129136 {
130137 if ( string . Equals ( enumItem . Key , flagValue , StringComparison . OrdinalIgnoreCase ) )
131138 {
@@ -146,15 +153,23 @@ public TEnum Read(ref Utf8JsonReader reader)
146153 }
147154
148155 TEnum enumValue = ( TEnum ) Enum . ToObject ( _EnumType , calculatedValue ) ;
149- if ( _TransformedToRaw . Count < 64 )
156+ if ( transformedToRaw . Count < MaximumAutoGrowthCacheSize )
150157 {
151- _TransformedToRaw [ enumString ] = new EnumInfo ( enumString , enumValue , calculatedValue ) ;
158+ lock ( _TransformedToRawCopyLockObject )
159+ {
160+ if ( ! _TransformedToRaw . ContainsKey ( enumString ) && _TransformedToRaw . Count < MaximumAutoGrowthCacheSize )
161+ {
162+ Dictionary < string , EnumInfo > transformedToRawCopy = new ( _TransformedToRaw ) ;
163+ transformedToRawCopy [ enumString ] = new EnumInfo ( enumString , enumValue , calculatedValue ) ;
164+ _TransformedToRaw = transformedToRawCopy ;
165+ }
166+ }
152167 }
153168 return enumValue ;
154169 }
155170
156171 // Case insensitive search attempted second.
157- foreach ( KeyValuePair < string , EnumInfo > enumItem in _TransformedToRaw )
172+ foreach ( KeyValuePair < string , EnumInfo > enumItem in transformedToRaw )
158173 {
159174 if ( string . Equals ( enumItem . Key , enumString , StringComparison . OrdinalIgnoreCase ) )
160175 {
@@ -232,7 +247,8 @@ public TEnum Read(ref Utf8JsonReader reader)
232247
233248 public void Write ( Utf8JsonWriter writer , TEnum value )
234249 {
235- if ( _RawToTransformed . TryGetValue ( value , out EnumInfo ? enumInfo ) )
250+ Dictionary < TEnum , EnumInfo > rawToTransformed = _RawToTransformed ;
251+ if ( rawToTransformed . TryGetValue ( value , out EnumInfo ? enumInfo ) )
236252 {
237253 writer . WriteStringValue ( enumInfo . Name ) ;
238254 return ;
@@ -244,8 +260,8 @@ public void Write(Utf8JsonWriter writer, TEnum value)
244260 {
245261 ulong calculatedValue = 0 ;
246262
247- StringBuilder Builder = new StringBuilder ( ) ;
248- foreach ( KeyValuePair < TEnum , EnumInfo > enumItem in _RawToTransformed )
263+ StringBuilder Builder = new ( ) ;
264+ foreach ( KeyValuePair < TEnum , EnumInfo > enumItem in rawToTransformed )
249265 {
250266 enumInfo = enumItem . Value ;
251267 if ( ! value . HasFlag ( enumInfo . EnumValue )
@@ -264,9 +280,17 @@ public void Write(Utf8JsonWriter writer, TEnum value)
264280 if ( calculatedValue == rawValue )
265281 {
266282 string finalName = Builder . ToString ( ) ;
267- if ( _RawToTransformed . Count < 64 )
283+ if ( rawToTransformed . Count < MaximumAutoGrowthCacheSize )
268284 {
269- _RawToTransformed [ value ] = new EnumInfo ( finalName , value , rawValue ) ;
285+ lock ( _RawToTransformedCopyLockObject )
286+ {
287+ if ( ! _RawToTransformed . ContainsKey ( value ) && _RawToTransformed . Count < MaximumAutoGrowthCacheSize )
288+ {
289+ Dictionary < TEnum , EnumInfo > rawToTransformedCopy = new ( _RawToTransformed ) ;
290+ rawToTransformedCopy [ value ] = new EnumInfo ( finalName , value , rawValue ) ;
291+ _RawToTransformed = rawToTransformedCopy ;
292+ }
293+ }
270294 }
271295 writer . WriteStringValue ( finalName ) ;
272296 return ;
0 commit comments