Uh oh!
There was an error while loading. Please reload this page.
Add logic to properly honor naming policy when serializing flag enums - #36726
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
steveharter
commented
May 20, 2020
Since naming policies are only one-way the resulting JSON that had a naming policy applied may not be able to be deserialized unless we also apply the naming policy to the CLR enum value names during deserialization (and match them up that way -- like we do with properties). |
layomia
commented
May 20, 2020
We already apply the naming policy when serializing, just incorrectly in the case of flags. This change doesn't prohibit any deserialization that was possible prior: Serializing Before: "compressed, IntegrityStream" Round tripping is not broken here because we do a case insensitive read with Enum.Parse. Serializing Before: "compressed, _integrity_stream" Neither of these strings can be read by Enum.Parse, as it expects some ordering of "Compressed, IntegrityStream". So, we are not breaking deserialization here, as it never worked for this scenario. Ultimately, correctly applying the naming won't affect reading, given the current deserialization implementation. The change is a prerequisite if we want to recognize the policy during deserialization (#31619) to enable roundtripping when a naming policy is used (one which does more than return a case-insensitive match). |
steveharter
commented
May 20, 2020
That works with camel-casing but not with snake-casing... |
layomia
commented
May 20, 2020
Yes, but we already honor snake-casing when serializing, and then can't deserialize the output: JsonSerializerOptionsoptions=newJsonSerializerOptions{Converters={newJsonStringEnumConverter(namingPolicy:newSimpleSnakeCasePolicy())}};FileAttributesval=FileAttributes.IntegrityStream;stringjson=JsonSerializer.Serialize(val,options);Console.WriteLine(json);// "integrity_stream"JsonSerializer.Deserialize<FileAttributes>(json,options);// JsonExceptionI'll reach out to discuss this offline. |
Uh oh!
There was an error while loading. Please reload this page.
…naming policy is not used
layomia
commented
May 21, 2020
Benchmarks for this change show serialization when a naming policy is used is up to ~2.48x faster when we have long enum representation. We also have less allocs (up to ~47% decrease) in these scenarios. This is due to creating and caching the Before
After
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
layomia
commented
Jun 2, 2020
Updated benchmark results following latest changes:
|
…, and add more tests
| @@ -16,32 +18,57 @@ internal class EnumConverter<T> : JsonConverter<T> | |||
| // Odd type codes are conveniently signed types (for enum backing types). | |||
| private static readonly string? s_negativeSign = ((int)s_enumTypeCode % 2) == 0 ? null : NumberFormatInfo.CurrentInfo.NegativeSign; | |||
There was a problem hiding this comment.
It's incorrect to cache any thread-local state (such as information about the thread-current culture) into a global static. The end result of this is that the very first time this code is executed, the executing thread's negative sign will be read and will be applied to all subsequent operations, regardless of what culture the other threads are running as.
If you wanted this to be properly culture-aware, you need to query the current thread's negative sign on every single call to IsValidIdentifier.
There was a problem hiding this comment.
This would be incorrect even if it was a thread-static, of course.
GrabYourPitchforks
commented
Jun 8, 2020
LGTM, thanks! :) |
Fixes#31622.