1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Collections;
6 using System.Diagnostics;
7 using System.Text.Json.Serialization.Converters;
9 namespace System.Text.Json
11 public static partial class JsonSerializer
13 private static void HandleStartDictionary(JsonSerializerOptions options, ref ReadStack state)
15 Debug.Assert(!state.Current.IsProcessingEnumerable());
17 JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;
18 if (jsonPropertyInfo == null)
20 jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options);
23 Debug.Assert(jsonPropertyInfo != null);
25 // A nested object or dictionary so push new frame.
26 if (state.Current.CollectionPropertyInitialized)
29 state.Current.JsonClassInfo = jsonPropertyInfo.ElementClassInfo;
30 state.Current.InitializeJsonPropertyInfo();
31 state.Current.CollectionPropertyInitialized = true;
33 ClassType classType = state.Current.JsonClassInfo.ClassType;
34 if (classType == ClassType.Value)
36 Type elementClassInfoType = jsonPropertyInfo.ElementClassInfo.Type;
37 if (elementClassInfoType != typeof(object) && elementClassInfoType != typeof(JsonElement))
39 ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type);
43 JsonClassInfo classInfo = state.Current.JsonClassInfo;
45 if (state.Current.IsProcessingIDictionaryConstructible())
47 state.Current.TempDictionaryValues = (IDictionary)classInfo.CreateConcreteDictionary();
51 if (classInfo.CreateObject == null)
53 ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type);
56 state.Current.ReturnValue = classInfo.CreateObject();
62 state.Current.CollectionPropertyInitialized = true;
64 if (state.Current.IsProcessingIDictionaryConstructible())
66 JsonClassInfo dictionaryClassInfo;
67 if (jsonPropertyInfo.DeclaredPropertyType == jsonPropertyInfo.ImplementedPropertyType)
69 dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.RuntimePropertyType);
73 dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.DeclaredPropertyType);
76 state.Current.TempDictionaryValues = (IDictionary)dictionaryClassInfo.CreateConcreteDictionary();
80 // Create the dictionary.
81 JsonClassInfo dictionaryClassInfo = jsonPropertyInfo.RuntimeClassInfo;
82 IDictionary value = (IDictionary)dictionaryClassInfo.CreateObject();
86 if (state.Current.ReturnValue != null)
88 state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
92 // A dictionary is being returned directly, or a nested dictionary.
93 state.Current.SetReturnValue(value);
99 private static void HandleEndDictionary(JsonSerializerOptions options, ref ReadStack state)
101 Debug.Assert(!state.Current.SkipProperty);
103 if (state.Current.IsProcessingProperty(ClassType.Dictionary))
105 // Handle special case of DataExtensionProperty where we just added a dictionary element to the extension property.
106 // Since the JSON value is not a dictionary element (it's a normal property in JSON) a JsonTokenType.EndObject
107 // encountered here is from the outer object so forward to HandleEndObject().
108 if (state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo)
110 HandleEndObject(ref state);
114 // We added the items to the dictionary already.
115 state.Current.EndProperty();
118 else if (state.Current.IsProcessingProperty(ClassType.IDictionaryConstructible))
120 Debug.Assert(state.Current.TempDictionaryValues != null);
121 JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
122 state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options));
123 state.Current.EndProperty();
128 if (state.Current.TempDictionaryValues != null)
130 JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
131 value = converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options);
135 value = state.Current.ReturnValue;
138 if (state.IsLastFrame)
140 // Set the return value directly since this will be returned to the user.
141 state.Current.Reset();
142 state.Current.ReturnValue = value;
147 ApplyObjectToEnumerable(value, ref state);