internal static void WriteDictionary <TProperty>(
            JsonConverter <TProperty> converter,
            JsonSerializerOptions options,
            ref WriteStackFrame current,
            Utf8JsonWriter writer)
        {
            if (converter == null)
            {
                return;
            }

            Debug.Assert(current.CollectionEnumerator != null);

            string    key;
            TProperty value;

            if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, TProperty> > enumerator)
            {
                // Avoid boxing for strongly-typed enumerators such as returned from IDictionary<string, TRuntimeProperty>
                value = enumerator.Current.Value;
                key   = enumerator.Current.Key;
            }
            else if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, object> > polymorphicEnumerator)
            {
                value = (TProperty)polymorphicEnumerator.Current.Value;
                key   = polymorphicEnumerator.Current.Key;
            }
            else if (current.IsIDictionaryConstructible || current.IsIDictionaryConstructibleProperty)
            {
                value = (TProperty)((DictionaryEntry)current.CollectionEnumerator.Current).Value;
                key   = (string)((DictionaryEntry)current.CollectionEnumerator.Current).Key;
            }
            else
            {
                // Todo: support non-generic Dictionary here (IDictionaryEnumerator)
                throw new NotSupportedException();
            }

            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());
                    }
                }

                JsonEncodedText escapedKey = JsonEncodedText.Encode(key, options.Encoder);
                writer.WritePropertyName(escapedKey);
                converter.Write(writer, value, options);
            }
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        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);
            }
        }
        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);
            }
        }
Пример #5
0
        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 (current.IsIDictionaryConstructible || current.IsIDictionaryConstructibleProperty)
            {
                key   = (string)((DictionaryEntry)current.CollectionEnumerator.Current).Key;
                value = (TProperty?)((DictionaryEntry)current.CollectionEnumerator.Current).Value;
            }

            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);
            }
        }
Пример #6
0
        private static bool HandleDictionary(
            JsonClassInfo elementClassInfo,
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo !;

            if (state.Current.CollectionEnumerator == null)
            {
                IEnumerable?enumerable = (IEnumerable?)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
                if (enumerable == null)
                {
                    if ((state.Current.JsonClassInfo !.ClassType != ClassType.Object ||        // Write null dictionary values
                         !jsonPropertyInfo.IgnoreNullValues) &&                                // Ignore ClassType.Object properties if IgnoreNullValues is true
                        state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing) // Ignore null extension property (which is a dictionary)
                    {
                        // Write a null object or enumerable.
                        state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, options, writeNull: true);
                    }

                    if (state.Current.PopStackOnEndCollection)
                    {
                        state.Pop();
                    }

                    return(true);
                }

                if (state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing)
                {
                    if (options.ReferenceHandling.ShouldWritePreservedReferences())
                    {
                        if (WriteReference(ref state, writer, options, ClassType.Dictionary, enumerable))
                        {
                            return(WriteEndDictionary(ref state));
                        }
                    }
                    else
                    {
                        state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, options);
                    }
                }

                // Let the dictionary return the default IEnumerator from its IEnumerable.GetEnumerator().
                // For IDictionary-derived classes this is normally be IDictionaryEnumerator.
                // For IDictionary<TKey, TVale>-derived classes this is normally IDictionaryEnumerator as well
                // but may be IEnumerable<KeyValuePair<TKey, TValue>> if the dictionary only supports generics.
                state.Current.CollectionEnumerator = enumerable.GetEnumerator();
            }

            if (state.Current.CollectionEnumerator.MoveNext())
            {
                // A dictionary should not have a null KeyValuePair.
                Debug.Assert(state.Current.CollectionEnumerator.Current != null);

                bool   obtainedValues = false;
                string?key            = default;
                object?value          = default;

                // Check for polymorphism.
                if (elementClassInfo.ClassType == ClassType.Unknown)
                {
                    jsonPropertyInfo.GetDictionaryKeyAndValue(ref state.Current, out key, out value);
                    GetRuntimeClassInfo(value, ref elementClassInfo, options);
                    obtainedValues = true;
                }

                if (elementClassInfo.ClassType == ClassType.Value)
                {
                    elementClassInfo.PolicyProperty !.WriteDictionary(ref state, writer);
                }
                else
                {
                    if (!obtainedValues)
                    {
                        jsonPropertyInfo.GetDictionaryKeyAndValue(ref state.Current, out key, out value);
                    }

                    if (options.DictionaryKeyPolicy != null && state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing)
                    {
                        Debug.Assert(key != null);
                        key = options.DictionaryKeyPolicy.ConvertName(key);
                        if (key == null)
                        {
                            ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(options.DictionaryKeyPolicy.GetType());
                        }
                    }

                    // An object or another enumerator requires a new stack frame.
                    state.Push(elementClassInfo, value);

                    state.Current.KeyName = key;
                }

                return(false);
            }

            // We are done enumerating.
            if (state.Current.ExtensionDataStatus == ExtensionDataWriteStatus.Writing)
            {
                state.Current.ExtensionDataStatus = ExtensionDataWriteStatus.Finished;
            }
            else
            {
                writer.WriteEndObject();
            }

            return(WriteEndDictionary(ref state));
        }
Пример #7
0
        private static void HandlePropertyName(
            JsonSerializerOptions options,
            ref Utf8JsonReader reader,
            ref ReadStack state)
        {
            if (state.Current.Drain)
            {
                return;
            }

            Debug.Assert(state.Current.ReturnValue != default || state.Current.TempDictionaryValues != default);
            Debug.Assert(state.Current.JsonClassInfo != default);

            if ((state.Current.IsProcessingDictionary || state.Current.IsProcessingIDictionaryConstructible) &&
                state.Current.JsonClassInfo.DataExtensionProperty != state.Current.JsonPropertyInfo)
            {
                string keyName = reader.GetString();

                if (options.DictionaryKeyPolicy != null)
                {
                    keyName = options.DictionaryKeyPolicy.ConvertName(keyName);

                    if (keyName == null)
                    {
                        ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(options.DictionaryKeyPolicy.GetType());
                    }

                    keyName = options.DictionaryKeyPolicy.ConvertName(keyName);
                }

                if (state.Current.IsDictionary || state.Current.IsIDictionaryConstructible)
                {
                    state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.PolicyProperty;
                }

                Debug.Assert(
                    state.Current.IsDictionary ||
                    (state.Current.IsDictionaryProperty && state.Current.JsonPropertyInfo != null) ||
                    state.Current.IsIDictionaryConstructible ||
                    (state.Current.IsIDictionaryConstructibleProperty && state.Current.JsonPropertyInfo != null));

                state.Current.KeyName = keyName;
            }
            else
            {
                state.Current.EndProperty();

                ReadOnlySpan <byte> propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
                if (reader._stringHasEscaping)
                {
                    int idx = propertyName.IndexOf(JsonConstants.BackSlash);
                    Debug.Assert(idx != -1);
                    propertyName = GetUnescapedString(propertyName, idx);
                }

                JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(propertyName, ref state.Current);
                if (jsonPropertyInfo == null)
                {
                    JsonPropertyInfo dataExtProperty = state.Current.JsonClassInfo.DataExtensionProperty;
                    if (dataExtProperty == null)
                    {
                        state.Current.JsonPropertyInfo = JsonPropertyInfo.s_missingProperty;
                    }
                    else
                    {
                        state.Current.JsonPropertyInfo = dataExtProperty;
                        state.Current.JsonPropertyName = propertyName.ToArray();
                        state.Current.KeyName          = JsonHelpers.Utf8GetString(propertyName);
                        state.Current.CollectionPropertyInitialized = true;

                        CreateDataExtensionProperty(dataExtProperty, ref state);
                    }
                }
                else
                {
                    // Support JsonException.Path.
                    Debug.Assert(
                        jsonPropertyInfo.JsonPropertyName == null ||
                        options.PropertyNameCaseInsensitive ||
                        propertyName.SequenceEqual(jsonPropertyInfo.JsonPropertyName));

                    state.Current.JsonPropertyInfo = jsonPropertyInfo;

                    if (jsonPropertyInfo.JsonPropertyName == null)
                    {
                        byte[] propertyNameArray = propertyName.ToArray();
                        if (options.PropertyNameCaseInsensitive)
                        {
                            // Each payload can have a different name here; remember the value on the temporary stack.
                            state.Current.JsonPropertyName = propertyNameArray;
                        }
                        else
                        {
                            // Prevent future allocs by caching globally on the JsonPropertyInfo which is specific to a Type+PropertyName
                            // so it will match the incoming payload except when case insensitivity is enabled (which is handled above).
                            state.Current.JsonPropertyInfo.JsonPropertyName = propertyNameArray;
                        }
                    }

                    state.Current.PropertyIndex++;
                }
            }
        }