-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add support for non-string Tkey on Dictionary #32909
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 |
|---|---|---|
|
|
@@ -2,6 +2,9 @@ | |
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // See the LICENSE file in the project root for more information. | ||
|
|
||
| using System.Buffers.Text; | ||
| using System.Collections.Generic; | ||
| using System.ComponentModel; | ||
| using System.Diagnostics; | ||
| using System.Diagnostics.CodeAnalysis; | ||
|
|
||
|
|
@@ -10,13 +13,13 @@ namespace System.Text.Json.Serialization.Converters | |
| /// <summary> | ||
| /// Default base class implementation of <cref>JsonDictionaryConverter{TCollection}</cref> . | ||
| /// </summary> | ||
| internal abstract class DictionaryDefaultConverter<TCollection, TValue> | ||
| : JsonDictionaryConverter<TCollection> | ||
| internal abstract class DictionaryDefaultConverter<TCollection, TKey, TValue> | ||
| : JsonDictionaryConverter<TCollection> where TKey : notnull | ||
| { | ||
| /// <summary> | ||
| /// When overridden, adds the value to the collection. | ||
| /// </summary> | ||
| protected abstract void Add(TValue value, JsonSerializerOptions options, ref ReadStack state); | ||
| protected abstract void Add(TKey key, TValue value, JsonSerializerOptions options, ref ReadStack state); | ||
|
|
||
| /// <summary> | ||
| /// When overridden, converts the temporary collection held in state.Current.ReturnValue to the final collection. | ||
|
|
@@ -31,6 +34,8 @@ protected virtual void CreateCollection(ref ReadStack state) { } | |
|
|
||
| internal override Type ElementType => typeof(TValue); | ||
|
|
||
| internal override Type KeyType => typeof(TKey); | ||
|
|
||
| protected static JsonConverter<TValue> GetElementConverter(ref ReadStack state) | ||
| { | ||
| JsonConverter<TValue> converter = (JsonConverter<TValue>)state.Current.JsonClassInfo.ElementClassInfo!.PolicyProperty!.ConverterBase; | ||
|
|
@@ -62,13 +67,19 @@ protected static JsonConverter<TValue> GetValueConverter(ref WriteStack state) | |
| return converter; | ||
| } | ||
|
|
||
| protected static KeyConverter<TKey> GetKeyConverter(JsonClassInfo classInfo) => (KeyConverter<TKey>)classInfo.KeyConverter; | ||
|
|
||
| internal sealed override bool OnTryRead( | ||
| ref Utf8JsonReader reader, | ||
| Type typeToConvert, | ||
| JsonSerializerOptions options, | ||
| ref ReadStack state, | ||
| [MaybeNullWhen(false)] out TCollection value) | ||
| { | ||
| // Get the key converter at the very beginning; will throw NSE if there is no converter for TKey. | ||
| // This is performed at the very beginning to avoid processing unsupported types. | ||
| KeyConverter<TKey> keyConverter = GetKeyConverter(state.Current.JsonClassInfo); | ||
|
|
||
| bool shouldReadPreservedReferences = options.ReferenceHandling.ShouldReadPreservedReferences(); | ||
|
|
||
| if (!state.SupportContinuation && !shouldReadPreservedReferences) | ||
|
|
@@ -102,11 +113,12 @@ internal sealed override bool OnTryRead( | |
| } | ||
|
|
||
| state.Current.JsonPropertyNameAsString = reader.GetString(); | ||
|
Contributor
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. Do we still need to set
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. Since We can remove it once we spread the
Contributor
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. To keep the code clean/consistent (and to avoid the unnecessary |
||
| keyConverter.OnTryRead(ref reader, keyConverter.TypeToConvert, options, ref state, out TKey key); | ||
|
|
||
| // Read the value and add. | ||
| reader.ReadWithVerify(); | ||
| TValue element = elementConverter.Read(ref reader, typeof(TValue), options); | ||
| Add(element, options, ref state); | ||
| Add(key, element, options, ref state); | ||
| } | ||
| } | ||
| else | ||
|
|
@@ -127,13 +139,14 @@ internal sealed override bool OnTryRead( | |
| ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); | ||
| } | ||
|
|
||
| state.Current.JsonPropertyNameAsString = reader.GetString(); | ||
| state.Current.JsonPropertyNameAsString = reader.GetString()!; | ||
| keyConverter.OnTryRead(ref reader, keyConverter.TypeToConvert, options, ref state, out TKey key); | ||
|
|
||
| reader.ReadWithVerify(); | ||
|
|
||
| // Get the value from the converter and add it. | ||
| elementConverter.TryRead(ref reader, typeof(TValue), options, ref state, out TValue element); | ||
| Add(element, options, ref state); | ||
| Add(key, element, options, ref state); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -219,16 +232,16 @@ internal sealed override bool OnTryRead( | |
|
|
||
| state.Current.PropertyState = StackFramePropertyState.Name; | ||
|
|
||
| ReadOnlySpan<byte> propertyName = reader.GetSpan(); | ||
| // Verify property doesn't contain metadata. | ||
| if (shouldReadPreservedReferences) | ||
| { | ||
| ReadOnlySpan<byte> propertyName = reader.GetSpan(); | ||
| if (propertyName.Length > 0 && propertyName[0] == '$') | ||
| { | ||
| ThrowHelper.ThrowUnexpectedMetadataException(propertyName, ref reader, ref state); | ||
| } | ||
| } | ||
|
|
||
| state.Current.DictionaryKeyName = propertyName.ToArray(); | ||
| state.Current.JsonPropertyNameAsString = reader.GetString(); | ||
| } | ||
|
|
||
|
|
@@ -245,6 +258,8 @@ internal sealed override bool OnTryRead( | |
|
|
||
| if (state.Current.PropertyState < StackFramePropertyState.TryRead) | ||
| { | ||
| keyConverter.OnTryRead(ref reader, keyConverter.TypeToConvert, options, ref state, out TKey key); | ||
|
|
||
| // Get the value from the converter and add it. | ||
| bool success = elementConverter.TryRead(ref reader, typeof(TValue), options, ref state, out TValue element); | ||
| if (!success) | ||
|
|
@@ -253,7 +268,7 @@ internal sealed override bool OnTryRead( | |
| return false; | ||
| } | ||
|
|
||
| Add(element, options, ref state); | ||
| Add(key, element, options, ref state); | ||
| state.Current.EndElement(); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,10 +13,10 @@ namespace System.Text.Json.Serialization.Converters | |
| /// representing the dictionary element key and value. | ||
| /// </summary> | ||
| internal sealed class IDictionaryConverter<TCollection> | ||
| : DictionaryDefaultConverter<TCollection, object?> | ||
| : DictionaryDefaultConverter<TCollection, string, object?> | ||
| where TCollection : IDictionary | ||
| { | ||
| protected override void Add(object? value, JsonSerializerOptions options, ref ReadStack state) | ||
| protected override void Add(string _, object? value, JsonSerializerOptions options, ref ReadStack state) | ||
|
Contributor
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. Would should use the |
||
| { | ||
| Debug.Assert(state.Current.ReturnValue is IDictionary); | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.