public override IEnumerable CreateDerivedEnumerableInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IList sourceList) { // Implementing types that don't have default constructors are not supported for deserialization. if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( collectionPropertyInfo.DeclaredPropertyType, collectionPropertyInfo.ParentClassType, collectionPropertyInfo.PropertyInfo); } object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject(); if (instance is IList instanceOfIList) { if (!instanceOfIList.IsReadOnly) { foreach (object item in sourceList) { instanceOfIList.Add(item); } return(instanceOfIList); } } else if (instance is ICollection <TRuntimeProperty> instanceOfICollection) { if (!instanceOfICollection.IsReadOnly) { foreach (TRuntimeProperty item in sourceList) { instanceOfICollection.Add(item); } return(instanceOfICollection); } } else if (instance is Stack <TRuntimeProperty> instanceOfStack) { foreach (TRuntimeProperty item in sourceList) { instanceOfStack.Push(item); } return(instanceOfStack); } else if (instance is Queue <TRuntimeProperty> instanceOfQueue) { foreach (TRuntimeProperty item in sourceList) { instanceOfQueue.Enqueue(item); } return(instanceOfQueue); } // TODO (https://github.com/dotnet/corefx/issues/40479): // Use reflection to support types implementing Stack or Queue. throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( collectionPropertyInfo.DeclaredPropertyType, collectionPropertyInfo.ParentClassType, collectionPropertyInfo.PropertyInfo); }
public override object CreateDerivedDictionaryInstance(JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options) { object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject(); if (instance is IDictionary instanceOfIDictionary) { if (!instanceOfIDictionary.IsReadOnly) { foreach (DictionaryEntry entry in sourceDictionary) { instanceOfIDictionary.Add((string)entry.Key, entry.Value); } return(instanceOfIDictionary); } } else if (instance is IDictionary <string, TRuntimeProperty> instanceOfGenericIDictionary) { if (!instanceOfGenericIDictionary.IsReadOnly) { foreach (DictionaryEntry entry in sourceDictionary) { instanceOfGenericIDictionary.Add((string)entry.Key, (TRuntimeProperty)entry.Value); } return(instanceOfGenericIDictionary); } } // TODO: Use reflection to support types implementing SortedList and maybe immutable dictionaries. // Types implementing SortedList and immutable dictionaries will fail here. throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( collectionPropertyInfo.DeclaredPropertyType, collectionPropertyInfo.ParentClassType, collectionPropertyInfo.PropertyInfo); }
public void GetDictionaryKeyAndValue(ref WriteStackFrame writeStackFrame, out string key, out object value) { Debug.Assert(ClassType == ClassType.Dictionary); if (writeStackFrame.CollectionEnumerator is IDictionaryEnumerator iDictionaryEnumerator) { if (iDictionaryEnumerator.Key is string keyAsString) { // Since IDictionaryEnumerator is not based on generics we can obtain the value directly. key = keyAsString; value = iDictionaryEnumerator.Value; } else { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( writeStackFrame.JsonPropertyInfo.DeclaredPropertyType, writeStackFrame.JsonPropertyInfo.ParentClassType, writeStackFrame.JsonPropertyInfo.PropertyInfo); } } else { // Forward to the generic dictionary. DictionaryValuePropertyPolicy.GetDictionaryKeyAndValueFromGenericDictionary(ref writeStackFrame, out key, out value); } }
public void DetermineEnumerablePopulationStrategy(object targetEnumerable) { if (JsonPropertyInfo.RuntimeClassInfo.AddItemToObject != null) { if (!JsonPropertyInfo.TryCreateEnumerableAddMethod(targetEnumerable, out object addMethodDelegate)) { // No "add" method for this collection, hence, not supported for deserialization. throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( JsonPropertyInfo.DeclaredPropertyType, JsonPropertyInfo.ParentClassType, JsonPropertyInfo.PropertyInfo); } AddObjectToEnumerable = addMethodDelegate; } else if (targetEnumerable is IList targetList) { if (targetList.IsReadOnly) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( JsonPropertyInfo.DeclaredPropertyType, JsonPropertyInfo.ParentClassType, JsonPropertyInfo.PropertyInfo); } } // If there's no add method, and we can't cast to IList, this collection is not supported for deserialization. else { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( JsonPropertyInfo.DeclaredPropertyType, JsonPropertyInfo.ParentClassType, JsonPropertyInfo.PropertyInfo); } }
public override ImmutableCollectionCreator ImmutableDictionaryCreateRange(Type constructingType, Type collectionType, Type elementType) { Debug.Assert(collectionType.IsGenericType); // Only string keys are allowed. if (collectionType.GetGenericArguments()[0] != typeof(string)) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(collectionType, parentType: null, memberInfo: null); } MethodInfo createRange = ImmutableDictionaryCreateRangeMethod(constructingType, elementType); if (createRange == null) { return(null); } Type creatorType = typeof(ImmutableDictionaryCreator <,>).MakeGenericType(elementType, collectionType); ConstructorInfo constructor = creatorType.GetConstructor( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null); ImmutableCollectionCreator creator = (ImmutableCollectionCreator)constructor.Invoke(Array.Empty <object>()); creator.RegisterCreatorDelegateFromMethod(createRange); return(creator); }
internal static void WriteDictionary <TProperty>( JsonConverter <TProperty> converter, JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer) { Debug.Assert(converter != null && current.CollectionEnumerator != null); string key; TProperty value; if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, TProperty> > enumerator) { key = enumerator.Current.Key; value = enumerator.Current.Value; } else if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, object> > polymorphicEnumerator) { key = polymorphicEnumerator.Current.Key; value = (TProperty)polymorphicEnumerator.Current.Value; } else { if (((DictionaryEntry)current.CollectionEnumerator.Current).Key is string keyAsString) { key = keyAsString; value = (TProperty)((DictionaryEntry)current.CollectionEnumerator.Current).Value; } else { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( current.JsonPropertyInfo.DeclaredPropertyType, current.JsonPropertyInfo.ParentClassType, current.JsonPropertyInfo.PropertyInfo); } } if (value == null) { writer.WriteNull(key); } else { if (options.DictionaryKeyPolicy != null && current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing) // We do not convert extension data. { key = options.DictionaryKeyPolicy.ConvertName(key); if (key == null) { ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(options.DictionaryKeyPolicy.GetType()); } } writer.WritePropertyName(key); converter.Write(writer, value, options); } }
public void DetermineIfDictionaryCanBePopulated(object targetDictionary) { if (!JsonPropertyInfo.CanPopulateDictionary(targetDictionary)) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( JsonPropertyInfo.DeclaredPropertyType, JsonPropertyInfo.ParentClassType, JsonPropertyInfo.PropertyInfo); } }
protected override void OnWriteDictionary(ref WriteStackFrame current, Utf8JsonWriter writer) { Debug.Assert(Converter != null && current.CollectionEnumerator != null); string key = null; TProperty?value = null; if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, TProperty?> > enumerator) { key = enumerator.Current.Key; value = enumerator.Current.Value; } else { if (((DictionaryEntry)current.CollectionEnumerator.Current).Key is string keyAsString) { key = keyAsString; value = (TProperty?)((DictionaryEntry)current.CollectionEnumerator.Current).Value; } else { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( current.JsonPropertyInfo.DeclaredPropertyType, current.JsonPropertyInfo.ParentClassType, current.JsonPropertyInfo.PropertyInfo); } } Debug.Assert(key != null); if (Options.DictionaryKeyPolicy != null) { // We should not be in the Nullable-value implementation branch for extension data. // (TValue should be typeof(object) or typeof(JsonElement)). Debug.Assert(current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing); key = Options.DictionaryKeyPolicy.ConvertName(key); if (key == null) { ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(Options.DictionaryKeyPolicy.GetType()); } } if (value == null) { writer.WriteNull(key); } else { writer.WritePropertyName(key); Converter.Write(writer, value.GetValueOrDefault(), Options); } }
public override void AddObjectToParentDictionary(object target, string key, object value) { if (target is IDictionary <string, TDeclaredProperty> genericDict) { Debug.Assert(!genericDict.IsReadOnly); genericDict[key] = (TDeclaredProperty)value; } else { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(target.GetType(), parentType: null, memberInfo: null); } }
public override IEnumerable CreateDerivedEnumerableInstance(JsonPropertyInfo collectionPropertyInfo, IList sourceList, string jsonPath, JsonSerializerOptions options) { object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject(); if (instance is IList instanceOfIList) { if (!instanceOfIList.IsReadOnly) { foreach (object item in sourceList) { instanceOfIList.Add(item); } return(instanceOfIList); } } else if (instance is ICollection <TRuntimeProperty> instanceOfICollection) { if (!instanceOfICollection.IsReadOnly) { foreach (TRuntimeProperty item in sourceList) { instanceOfICollection.Add(item); } return(instanceOfICollection); } } else if (instance is Stack <TRuntimeProperty> instanceOfStack) { foreach (TRuntimeProperty item in sourceList) { instanceOfStack.Push(item); } return(instanceOfStack); } else if (instance is Queue <TRuntimeProperty> instanceOfQueue) { foreach (TRuntimeProperty item in sourceList) { instanceOfQueue.Enqueue(item); } return(instanceOfQueue); } // TODO: Use reflection to support types implementing Stack or Queue. throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( collectionPropertyInfo.DeclaredPropertyType, collectionPropertyInfo.ParentClassType, collectionPropertyInfo.PropertyInfo); }
protected override void OnWriteDictionary(ref WriteStackFrame current, Utf8JsonWriter writer) { Debug.Assert(Converter != null && current.CollectionEnumerator != null); string key = null; TProperty?value = null; if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, TProperty?> > enumerator) { key = enumerator.Current.Key; value = enumerator.Current.Value; } else { if (((DictionaryEntry)current.CollectionEnumerator.Current).Key is string keyAsString) { key = keyAsString; value = (TProperty?)((DictionaryEntry)current.CollectionEnumerator.Current).Value; } else { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( current.JsonPropertyInfo.DeclaredPropertyType, current.JsonPropertyInfo.ParentClassType, current.JsonPropertyInfo.PropertyInfo); } } Debug.Assert(key != null); if (value == null) { writer.WriteNull(key); } else { if (Options.DictionaryKeyPolicy != null) { key = Options.DictionaryKeyPolicy.ConvertName(key); if (key == null) { ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(Options.DictionaryKeyPolicy.GetType()); } } writer.WritePropertyName(key); Converter.Write(writer, value.GetValueOrDefault(), Options); } }
public override void GetDictionaryKeyAndValueFromGenericDictionary(ref WriteStackFrame writeStackFrame, out string key, out object value) { if (writeStackFrame.CollectionEnumerator is IEnumerator <KeyValuePair <string, TDeclaredProperty> > genericEnumerator) { key = genericEnumerator.Current.Key; value = genericEnumerator.Current.Value; } else { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( writeStackFrame.JsonPropertyInfo.DeclaredPropertyType, writeStackFrame.JsonPropertyInfo.ParentClassType, writeStackFrame.JsonPropertyInfo.PropertyInfo); } }
public override ImmutableCollectionCreator ImmutableDictionaryCreateRange(Type constructingType, Type collectionType, Type elementType) { Debug.Assert(collectionType.IsGenericType); // Only string keys are allowed. if (collectionType.GetGenericArguments()[0] != typeof(string)) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(collectionType, parentType: null, memberInfo: null); } MethodInfo createRange = ImmutableDictionaryCreateRangeMethod(constructingType, elementType); if (createRange == null) { return(null); } Type creatorType = typeof(ImmutableDictionaryCreator <,>).MakeGenericType(elementType, collectionType); ConstructorInfo realMethod = creatorType.GetConstructor( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null); Debug.Assert(realMethod != null); var dynamicMethod = new DynamicMethod( ConstructorInfo.ConstructorName, typeof(object), Type.EmptyTypes, typeof(ReflectionEmitMemberAccessor).Module, skipVisibility: true); ILGenerator generator = dynamicMethod.GetILGenerator(); generator.Emit(OpCodes.Newobj, realMethod); generator.Emit(OpCodes.Ret); JsonClassInfo.ConstructorDelegate constructor = (JsonClassInfo.ConstructorDelegate)dynamicMethod.CreateDelegate( typeof(JsonClassInfo.ConstructorDelegate)); ImmutableCollectionCreator creator = (ImmutableCollectionCreator)constructor(); creator.RegisterCreatorDelegateFromMethod(createRange); return(creator); }
private void DetermineSerializationCapabilities() { if ((ClassType & (ClassType.Enumerable | ClassType.Dictionary)) == 0) { // We serialize if there is a getter + not ignoring readonly properties. ShouldSerialize = HasGetter && (HasSetter || !Options.IgnoreReadOnlyProperties); // We deserialize if there is a setter. ShouldDeserialize = HasSetter; } else { if (HasGetter) { ShouldSerialize = true; if (HasSetter) { ShouldDeserialize = true; if (RuntimePropertyType.IsArray) { // Verify that we don't have a multidimensional array. if (RuntimePropertyType.GetArrayRank() > 1) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(RuntimePropertyType, ParentClassType, PropertyInfo); } EnumerableConverter = s_jsonArrayConverter; } else if (ClassType == ClassType.Dictionary && DefaultImmutableDictionaryConverter.IsImmutableDictionary(RuntimePropertyType)) { DefaultImmutableDictionaryConverter.RegisterImmutableDictionary(RuntimePropertyType, ElementType, Options); DictionaryConverter = s_jsonImmutableDictionaryConverter; } else if (ClassType == ClassType.Enumerable && DefaultImmutableEnumerableConverter.IsImmutableEnumerable(RuntimePropertyType, out bool isImmutableArray)) { DefaultImmutableEnumerableConverter.RegisterImmutableCollection(RuntimePropertyType, ElementType, Options); EnumerableConverter = s_jsonImmutableEnumerableConverter; IsImmutableArray = isImmutableArray; } } } } }
public override object CreateDerivedDictionaryInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary) { // Implementing types that don't have default constructors are not supported for deserialization. if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( collectionPropertyInfo.DeclaredPropertyType, collectionPropertyInfo.ParentClassType, collectionPropertyInfo.PropertyInfo); } object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject(); if (instance is IDictionary instanceOfIDictionary) { if (!instanceOfIDictionary.IsReadOnly) { foreach (DictionaryEntry entry in sourceDictionary) { instanceOfIDictionary.Add((string)entry.Key, entry.Value); } return(instanceOfIDictionary); } } else if (instance is IDictionary <string, TRuntimeProperty> instanceOfGenericIDictionary) { if (!instanceOfGenericIDictionary.IsReadOnly) { foreach (DictionaryEntry entry in sourceDictionary) { instanceOfGenericIDictionary.Add((string)entry.Key, (TRuntimeProperty)entry.Value); } return(instanceOfGenericIDictionary); } } // TODO (https://github.com/dotnet/corefx/issues/40479): // Use reflection to support types implementing SortedList and maybe immutable dictionaries. // Types implementing SortedList and immutable dictionaries will fail here. throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( collectionPropertyInfo.DeclaredPropertyType, collectionPropertyInfo.ParentClassType, collectionPropertyInfo.PropertyInfo); }
public static object CreateEnumerableValue(ref ReadStack state) { JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; // If the property has an EnumerableConverter, then we use tempEnumerableValues. if (jsonPropertyInfo.EnumerableConverter != null) { IList converterList; JsonClassInfo elementClassInfo = jsonPropertyInfo.ElementClassInfo; if (elementClassInfo.ClassType == ClassType.Value) { converterList = elementClassInfo.PolicyProperty.CreateConverterList(); } else { converterList = new List <object>(); } state.Current.TempEnumerableValues = converterList; // Clear the value if present to ensure we don't confuse tempEnumerableValues with the collection. if (!jsonPropertyInfo.IsPropertyPolicy && !state.Current.JsonPropertyInfo.IsImmutableArray) { jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null); } return(null); } JsonClassInfo runtimeClassInfo = jsonPropertyInfo.RuntimeClassInfo; if (runtimeClassInfo.CreateObject != null) { return(runtimeClassInfo.CreateObject()); } else { // Could not create an instance to be returned. For derived types, this means there is no parameterless ctor. throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( jsonPropertyInfo.DeclaredPropertyType, jsonPropertyInfo.ParentClassType, jsonPropertyInfo.PropertyInfo); } }
// Return the element type of the IEnumerable or return null if not an IEnumerable. public static Type GetElementType(Type propertyType, Type parentType, MemberInfo memberInfo, JsonSerializerOptions options) { if (!typeof(IEnumerable).IsAssignableFrom(propertyType)) { return(null); } // Check for Array. Type elementType = propertyType.GetElementType(); if (elementType != null) { return(elementType); } // Check for Dictionary<TKey, TValue> or IEnumerable<T> if (propertyType.IsGenericType) { Type[] args = propertyType.GetGenericArguments(); ClassType classType = GetClassType(propertyType, options); if ((classType == ClassType.Dictionary || classType == ClassType.IDictionaryConstructible) && args.Length >= 2 && // It is >= 2 in case there is a IDictionary<TKey, TValue, TSomeExtension>. args[0].UnderlyingSystemType == typeof(string)) { return(args[1]); } if (classType == ClassType.Enumerable && args.Length >= 1) // It is >= 1 in case there is an IEnumerable<T, TSomeExtension>. { return(args[0]); } } if (propertyType.IsAssignableFrom(typeof(IList)) || propertyType.IsAssignableFrom(typeof(IDictionary)) || IsDeserializedByConstructingWithIList(propertyType) || IsDeserializedByConstructingWithIDictionary(propertyType)) { return(typeof(object)); } throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(propertyType, parentType, memberInfo); }
public override IEnumerable CreateDerivedEnumerableInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IList sourceList) { // Implementing types that don't have default constructors are not supported for deserialization. if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection( collectionPropertyInfo.DeclaredPropertyType, collectionPropertyInfo.ParentClassType, collectionPropertyInfo.PropertyInfo); } object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject(); if (instance is IList instanceOfIList && !instanceOfIList.IsReadOnly) { foreach (object item in sourceList) { instanceOfIList.Add(item); } return(instanceOfIList); }
private void DetermineSerializationCapabilities() { if (ClassType != ClassType.Enumerable && ClassType != ClassType.Dictionary && ClassType != ClassType.IDictionaryConstructible) { // We serialize if there is a getter + not ignoring readonly properties. ShouldSerialize = HasGetter && (HasSetter || !Options.IgnoreReadOnlyProperties); // We deserialize if there is a setter. ShouldDeserialize = HasSetter; } else { if (HasGetter) { ShouldSerialize = true; if (HasSetter) { ShouldDeserialize = true; if (RuntimePropertyType.IsArray) { // Verify that we don't have a multidimensional array. if (RuntimePropertyType.GetArrayRank() > 1) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(RuntimePropertyType, ParentClassType, PropertyInfo); } EnumerableConverter = s_jsonArrayConverter; } else if (ClassType == ClassType.IDictionaryConstructible) { // Natively supported type. if (DeclaredPropertyType == ImplementedPropertyType) { if (RuntimePropertyType.FullName.StartsWith(JsonClassInfo.ImmutableNamespaceName)) { DefaultImmutableDictionaryConverter.RegisterImmutableDictionary( RuntimePropertyType, JsonClassInfo.GetElementType(RuntimePropertyType, ParentClassType, PropertyInfo, Options), Options); DictionaryConverter = s_jsonImmutableDictionaryConverter; } else if (JsonClassInfo.IsDeserializedByConstructingWithIDictionary(RuntimePropertyType)) { DictionaryConverter = s_jsonIDictionaryConverter; } } // Type that implements a type with ClassType IDictionaryConstructible. else { DictionaryConverter = s_jsonDerivedDictionaryConverter; } } else if (ClassType == ClassType.Enumerable) { // Else if it's an implementing type whose runtime type is not assignable to IList. if (DeclaredPropertyType != ImplementedPropertyType && (!typeof(IList).IsAssignableFrom(RuntimePropertyType) || ImplementedPropertyType == typeof(ArrayList) || ImplementedPropertyType == typeof(IList))) { EnumerableConverter = s_jsonDerivedEnumerableConverter; } else if (JsonClassInfo.IsDeserializedByConstructingWithIList(RuntimePropertyType) || (!typeof(IList).IsAssignableFrom(RuntimePropertyType) && JsonClassInfo.HasConstructorThatTakesGenericIEnumerable(RuntimePropertyType, Options))) { EnumerableConverter = s_jsonICollectionConverter; } else if (RuntimePropertyType.IsGenericType && RuntimePropertyType.FullName.StartsWith(JsonClassInfo.ImmutableNamespaceName) && RuntimePropertyType.GetGenericArguments().Length == 1) { DefaultImmutableEnumerableConverter.RegisterImmutableCollection(RuntimePropertyType, JsonClassInfo.GetElementType(RuntimePropertyType, ParentClassType, PropertyInfo, Options), Options); EnumerableConverter = s_jsonImmutableEnumerableConverter; } } } } } }
// If this method is changed, also change ApplyObjectToEnumerable. internal static void ApplyValueToEnumerable <TProperty>( ref TProperty value, ref ReadStack state) { Debug.Assert(!state.Current.SkipProperty); if (state.Current.IsProcessingObject(ClassType.Enumerable)) { if (state.Current.TempEnumerableValues != null) { ((IList <TProperty>)state.Current.TempEnumerableValues).Add(value); } else { AddValueToEnumerable(ref state, state.Current.ReturnValue, value); } } else if (state.Current.IsProcessingProperty(ClassType.Enumerable)) { if (state.Current.TempEnumerableValues != null) { ((IList <TProperty>)state.Current.TempEnumerableValues).Add(value); } else { Debug.Assert(state.Current.JsonPropertyInfo != null); Debug.Assert(state.Current.ReturnValue != null); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; object?currentEnumerable = jsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue); if (currentEnumerable == null) { jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value); } else { AddValueToEnumerable(ref state, currentEnumerable, value); } } } else if (state.Current.IsProcessingDictionary()) { string?key = state.Current.KeyName; Debug.Assert(!string.IsNullOrEmpty(key)); if (state.Current.TempDictionaryValues != null) { ((IDictionary <string, TProperty>)state.Current.TempDictionaryValues)[key] = value; } else { Debug.Assert(state.Current.ReturnValue != null && state.Current.JsonPropertyInfo != null); object?currentDictionary = state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue); if (currentDictionary is IDictionary <string, TProperty> genericDict) { Debug.Assert(!genericDict.IsReadOnly); genericDict[key] = value; } else if (currentDictionary is IDictionary dict) { Debug.Assert(!dict.IsReadOnly); dict[key] = value; } else { Debug.Assert(currentDictionary != null); throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(currentDictionary.GetType(), parentType: null, memberInfo: null); } } } else { Debug.Assert(state.Current.JsonPropertyInfo != null); state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value); } }
private static void HandleStartDictionary(JsonSerializerOptions options, ref ReadStack state) { Debug.Assert(!state.Current.IsProcessingEnumerable()); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (jsonPropertyInfo == null) { jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options); } Debug.Assert(jsonPropertyInfo != null); // A nested object or dictionary so push new frame. if (state.Current.CollectionPropertyInitialized) { state.Push(); state.Current.JsonClassInfo = jsonPropertyInfo.ElementClassInfo; state.Current.InitializeJsonPropertyInfo(); JsonClassInfo classInfo = state.Current.JsonClassInfo; if (state.Current.IsProcessingIDictionaryConstructible()) { state.Current.TempDictionaryValues = (IDictionary)classInfo.CreateConcreteDictionary(); state.Current.CollectionPropertyInitialized = true; } else if (state.Current.IsProcessingDictionary()) { if (classInfo.CreateObject == null) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(classInfo.Type, parentType: null, memberInfo: null); } state.Current.ReturnValue = classInfo.CreateObject(); state.Current.CollectionPropertyInitialized = true; } else if (state.Current.IsProcessingObject(ClassType.Object)) { if (classInfo.CreateObject == null) { ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(classInfo.Type); } state.Current.ReturnValue = classInfo.CreateObject(); } else { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type); } return; } state.Current.CollectionPropertyInitialized = true; if (state.Current.IsProcessingIDictionaryConstructible()) { JsonClassInfo dictionaryClassInfo; if (jsonPropertyInfo.DeclaredPropertyType == jsonPropertyInfo.ImplementedPropertyType) { dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.RuntimePropertyType); } else { dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.DeclaredPropertyType); } state.Current.TempDictionaryValues = (IDictionary)dictionaryClassInfo.CreateConcreteDictionary(); } else { // Create the dictionary. JsonClassInfo dictionaryClassInfo = jsonPropertyInfo.RuntimeClassInfo; IDictionary value = (IDictionary)dictionaryClassInfo.CreateObject(); if (value != null) { if (state.Current.ReturnValue != null) { state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value); } else { // A dictionary is being returned directly, or a nested dictionary. state.Current.SetReturnValue(value); } } } }
private static void HandleStartObject(JsonSerializerOptions options, ref ReadStack state) { Debug.Assert(!state.Current.IsProcessingDictionaryOrIDictionaryConstructible()); // Note: unless we are a root object, we are going to push a property onto the ReadStack // in the if/else if check below. if (state.Current.IsProcessingEnumerable()) { // A nested object within an enumerable (non-dictionary). if (!state.Current.CollectionPropertyInitialized) { // We have bad JSON: enumerable element appeared without preceding StartArray token. ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonPropertyInfo.DeclaredPropertyType); } Type objType = state.Current.GetElementType(); state.Push(); state.Current.Initialize(objType, options); } else if (state.Current.JsonPropertyInfo != null) { // Nested object within an object. Debug.Assert(state.Current.IsProcessingObject(ClassType.Object)); Type objType = state.Current.JsonPropertyInfo.RuntimePropertyType; state.Push(); state.Current.Initialize(objType, options); } JsonClassInfo classInfo = state.Current.JsonClassInfo; if (state.Current.IsProcessingObject(ClassType.IDictionaryConstructible)) { state.Current.TempDictionaryValues = (IDictionary)classInfo.CreateConcreteDictionary(); state.Current.CollectionPropertyInitialized = true; } else if (state.Current.IsProcessingObject(ClassType.Dictionary)) { if (classInfo.CreateObject == null) { throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(classInfo.Type, parentType: null, memberInfo: null); } state.Current.ReturnValue = classInfo.CreateObject(); state.Current.CollectionPropertyInitialized = true; } else if (state.Current.IsProcessingObject(ClassType.Object)) { if (classInfo.CreateObject == null) { ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(classInfo.Type); } state.Current.ReturnValue = classInfo.CreateObject(); if (state.Current.IsProcessingDictionary()) { state.Current.CollectionPropertyInitialized = true; } } else { // Only dictionaries or objects are valid given the `StartObject` token. ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type); } }