// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization.Converters { /// <summary> /// Converter for <cref>System.Collections.Generic.IDictionary{TKey, TValue}</cref> that /// (de)serializes as a JSON object with properties representing the dictionary element key and value. /// </summary> internal sealed class IDictionaryOfTKeyTValueConverter<TDictionary, TKey, TValue> : DictionaryDefaultConverter<TDictionary, TKey, TValue> where TDictionary : IDictionary<TKey, TValue> where TKey : notnull { internal override bool CanPopulate => true; protected override void Add(TKey key, in TValue value, JsonSerializerOptions options, ref ReadStack state) { TDictionary collection = (TDictionary)state.Current.ReturnValue!; if (options.AllowDuplicateProperties) { collection[key] = value; } else { if (!collection.TryAdd(key, value)) { ThrowHelper.ThrowJsonException_DuplicatePropertyNotAllowed(); } } if (IsValueType) { state.Current.ReturnValue = collection; }; } protected override void CreateCollection(ref Utf8JsonReader reader, scoped ref ReadStack state) { base.CreateCollection(ref reader, ref state); TDictionary returnValue = (TDictionary)state.Current.ReturnValue!; if (returnValue.IsReadOnly) { state.Current.ReturnValue = null; // clear out for more accurate JsonPath reporting. ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(Type, ref reader, ref state); } } internal override void ConfigureJsonTypeInfo(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options) { // Deserialize as Dictionary<TKey,TValue> for interface types that support it. if (jsonTypeInfo.CreateObject is null && Type.IsAssignableFrom(typeof(Dictionary<TKey, TValue>))) { Debug.Assert(Type.IsInterface); jsonTypeInfo.CreateObject = () => new Dictionary<TKey, TValue>(); } } } } |