-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Lazily instantiate JsonSerializerOptions.Converters #77219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,7 @@ public sealed partial class JsonSerializerOptions | |
| /// <remarks> | ||
| /// Once serialization or deserialization occurs, the list cannot be modified. | ||
| /// </remarks> | ||
| public IList<JsonConverter> Converters => _converters; | ||
| public IList<JsonConverter> Converters => _converters ??= new ConverterList(this); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't thread-safe, in that two threads concurrently accessing this could end up getting different ConverterList instances. Is that ok? And, it seems like this could transition from null to non-null even after being marked as isreadonly. Is that ok?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's ok for both cases, all logic consuming that field (including equality comparison in the global cache) has been updated so that
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It can, of course, result in issues when multiple threads attempt to configure the same mutable instance, but generally speaking the type is not designed to be thread safe while mutable. |
||
|
|
||
| /// <summary> | ||
| /// Returns the converter for the specified type. | ||
|
|
@@ -66,11 +66,14 @@ internal JsonConverter GetConverterInternal(Type typeToConvert) | |
|
|
||
| internal JsonConverter? GetConverterFromList(Type typeToConvert) | ||
| { | ||
| foreach (JsonConverter item in _converters) | ||
| if (_converters != null) | ||
| { | ||
| if (item.CanConvert(typeToConvert)) | ||
| foreach (JsonConverter item in _converters) | ||
| { | ||
| return item; | ||
| if (item.CanConvert(typeToConvert)) | ||
| { | ||
| return item; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious - when converters are not null - what's the chance that someone cached converter but didn't cache options? Won't this converters check realistically always be false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly we could add equals and hash code to our implementations of converters and make them return trues when types match? That would make it relatively more likely to be true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would almost always be false, I wouldn't expect users to cache converters if they're not caching options.
It might also be false because some converters accept parameters. We want to avoid false positives under all circumstances since it would lead to observable bugs -- on the other hand we tolerate false negatives since they can only result in reduced performance.