JsonDictionaryConverter<TDictionary, TKey, TValue>
abstract class JsonDictionaryConverter<TDictionary, TKey, TValue> : JsonDictionaryConverter<TDictionary>
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
internal abstract class JsonDictionaryConverter<TDictionary, TKey, TValue> : JsonDictionaryConverter<TDictionary>
{
protected JsonConverter<TKey> _keyConverter;
protected JsonConverter<TValue> _valueConverter;
internal override Type ElementType => typeof(TValue);
internal override Type KeyType => typeof(TKey);
protected abstract void Add(TKey key, [In] [System.Runtime.CompilerServices.IsReadOnly] TValue value, JsonSerializerOptions options, ref ReadStack state);
protected virtual void ConvertCollection(ref ReadStack state, JsonSerializerOptions options)
{
}
protected virtual void CreateCollection(ref Utf8JsonReader reader, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state)
{
if (!(state.ParentProperty?.TryGetPrePopulatedValue(ref state) ?? false)) {
JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;
if (jsonTypeInfo.CreateObject == null)
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(jsonTypeInfo, ref reader, ref state);
state.Current.ReturnValue = jsonTypeInfo.CreateObject();
}
}
protected static JsonConverter<T> GetConverter<T>(JsonTypeInfo typeInfo)
{
return ((JsonTypeInfo<T>)typeInfo).EffectiveConverter;
}
internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TDictionary value)
{
JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;
JsonTypeInfo keyTypeInfo = jsonTypeInfo.KeyTypeInfo;
JsonTypeInfo elementTypeInfo = jsonTypeInfo.ElementTypeInfo;
bool isPopulatedValue;
if (!state.SupportContinuation && !state.Current.CanContainMetadata) {
if (reader.TokenType != JsonTokenType.StartObject)
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type);
CreateCollection(ref reader, ref state);
jsonTypeInfo.OnDeserializing?.Invoke(state.Current.ReturnValue);
if (_keyConverter == null)
_keyConverter = GetConverter<TKey>(keyTypeInfo);
if (_valueConverter == null)
_valueConverter = GetConverter<TValue>(elementTypeInfo);
if (_valueConverter.CanUseDirectReadOrWrite && !state.Current.NumberHandling.HasValue) {
while (true) {
ref reader.ReadWithVerify();
if (reader.TokenType == JsonTokenType.EndObject)
break;
state.Current.JsonPropertyInfo = keyTypeInfo.PropertyInfoForTypeInfo;
TKey key = <OnTryRead>g__ReadDictionaryKey|10_0(_keyConverter, ref reader, ref state, options);
ref reader.ReadWithVerify();
state.Current.JsonPropertyInfo = elementTypeInfo.PropertyInfoForTypeInfo;
TValue value2 = _valueConverter.Read(ref reader, ElementType, options);
this.Add(key, ref value2, options, ref state);
}
} else {
while (true) {
ref reader.ReadWithVerify();
if (reader.TokenType == JsonTokenType.EndObject)
break;
state.Current.JsonPropertyInfo = keyTypeInfo.PropertyInfoForTypeInfo;
TKey key2 = <OnTryRead>g__ReadDictionaryKey|10_0(_keyConverter, ref reader, ref state, options);
ref reader.ReadWithVerify();
state.Current.JsonPropertyInfo = elementTypeInfo.PropertyInfoForTypeInfo;
_valueConverter.TryRead(ref reader, ElementType, options, ref state, out TValue value3, out isPopulatedValue);
this.Add(key2, ref value3, options, ref state);
}
}
} else {
if (state.Current.ObjectState == StackFrameObjectState.None) {
if (reader.TokenType != JsonTokenType.StartObject)
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type);
state.Current.ObjectState = StackFrameObjectState.StartToken;
}
if (state.Current.CanContainMetadata && (int)state.Current.ObjectState < 2) {
if (!JsonSerializer.TryReadMetadata(this, jsonTypeInfo, ref reader, ref state)) {
value = default(TDictionary);
return false;
}
if (state.Current.MetadataPropertyNames == MetadataPropertyName.Ref) {
value = JsonSerializer.ResolveReferenceId<TDictionary>(ref state);
return true;
}
state.Current.ObjectState = StackFrameObjectState.ReadMetadata;
}
if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0 && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted) {
JsonConverter jsonConverter = ResolvePolymorphicConverter(jsonTypeInfo, ref state);
if (jsonConverter != null) {
object value4;
bool flag = jsonConverter.OnTryReadAsObject(ref reader, jsonConverter.Type, options, ref state, out value4);
value = (TDictionary)value4;
state.ExitPolymorphicConverter(flag);
return flag;
}
}
if ((int)state.Current.ObjectState < 4) {
if (state.Current.CanContainMetadata)
JsonSerializer.ValidateMetadataForObjectConverter(ref state);
CreateCollection(ref reader, ref state);
if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Id) != 0) {
state.ReferenceResolver.AddReference(state.ReferenceId, state.Current.ReturnValue);
state.ReferenceId = null;
}
jsonTypeInfo.OnDeserializing?.Invoke(state.Current.ReturnValue);
state.Current.ObjectState = StackFrameObjectState.CreatedObject;
}
if (_keyConverter == null)
_keyConverter = GetConverter<TKey>(keyTypeInfo);
if (_valueConverter == null)
_valueConverter = GetConverter<TValue>(elementTypeInfo);
while (true) {
if (state.Current.PropertyState == StackFramePropertyState.None) {
if (!reader.Read()) {
value = default(TDictionary);
return false;
}
state.Current.PropertyState = StackFramePropertyState.ReadName;
}
TKey val;
if ((int)state.Current.PropertyState < 2) {
if (reader.TokenType == JsonTokenType.EndObject)
break;
state.Current.PropertyState = StackFramePropertyState.Name;
if (state.Current.CanContainMetadata) {
ReadOnlySpan<byte> unescapedSpan = ref reader.GetUnescapedSpan();
if (JsonSerializer.IsMetadataPropertyName(unescapedSpan, state.Current.BaseJsonTypeInfo.PolymorphicTypeResolver)) {
if (options.AllowOutOfOrderMetadataProperties) {
ref reader.SkipWithVerify();
state.Current.EndElement();
continue;
}
ThrowHelper.ThrowUnexpectedMetadataException(unescapedSpan, ref reader, ref state);
}
}
state.Current.JsonPropertyInfo = keyTypeInfo.PropertyInfoForTypeInfo;
val = <OnTryRead>g__ReadDictionaryKey|10_0(_keyConverter, ref reader, ref state, options);
} else
val = (TKey)state.Current.DictionaryKey;
if ((int)state.Current.PropertyState < 3) {
if (!ref reader.TryAdvanceWithOptionalReadAhead(_valueConverter.RequiresReadAhead)) {
state.Current.DictionaryKey = val;
value = default(TDictionary);
return false;
}
state.Current.PropertyState = StackFramePropertyState.ReadValue;
}
if ((int)state.Current.PropertyState < 5) {
state.Current.JsonPropertyInfo = elementTypeInfo.PropertyInfoForTypeInfo;
if (!_valueConverter.TryRead(ref reader, typeof(TValue), options, ref state, out TValue value5, out isPopulatedValue)) {
state.Current.DictionaryKey = val;
value = default(TDictionary);
return false;
}
this.Add(val, ref value5, options, ref state);
state.Current.EndElement();
}
}
}
ConvertCollection(ref state, options);
object returnValue = state.Current.ReturnValue;
jsonTypeInfo.OnDeserialized?.Invoke(returnValue);
value = (TDictionary)returnValue;
return true;
}
internal sealed override bool OnTryWrite(Utf8JsonWriter writer, TDictionary dictionary, JsonSerializerOptions options, ref WriteStack state)
{
if (dictionary == null) {
writer.WriteNullValue();
return true;
}
JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;
if (!state.Current.ProcessedStartToken) {
state.Current.ProcessedStartToken = true;
jsonTypeInfo.OnSerializing?.Invoke(dictionary);
writer.WriteStartObject();
if (state.CurrentContainsMetadata && CanHaveMetadata)
JsonSerializer.WriteMetadataForObject(this, ref state, writer);
state.Current.JsonPropertyInfo = jsonTypeInfo.ElementTypeInfo.PropertyInfoForTypeInfo;
}
bool num = OnWriteResume(writer, dictionary, options, ref state);
if (num) {
if (!state.Current.ProcessedEndToken) {
state.Current.ProcessedEndToken = true;
writer.WriteEndObject();
}
Action<object> onSerialized = jsonTypeInfo.OnSerialized;
if (onSerialized == null)
return num;
onSerialized(dictionary);
}
return num;
}
}
}