Newtonsoft JSON.NET parse to array of custom key/value pair objects

后端 未结 2 612
春和景丽
春和景丽 2020-12-22 03:31

I have this strange issue with parsing given JSON data. I have this JSON structure:

{\"value\":[
  {\"street\":\"Karlova 25\"},
  {\"city\":\"Prague\"},
  {\         


        
2条回答
  •  感动是毒
    2020-12-22 04:22

    It appears that you want to represent a Dictionary in your JSON as an array of objects, where each nested object has one key and value from the dictionary. You can do it with the following converter:

    public class DictionaryToDictionaryListConverter : JsonConverter 
    {
        class DictionaryDTO : Dictionary
        {
            public DictionaryDTO(KeyValuePair pair) : base(1) { Add(pair.Key, pair.Value); }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return typeof(IDictionary).IsAssignableFrom(objectType) && objectType != typeof(DictionaryDTO);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var token = JToken.Load(reader);
            var dict = (IDictionary)(existingValue as IDictionary ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
            if (token.Type == JTokenType.Array)
            {
                foreach (var item in token)
                    using (var subReader = item.CreateReader())
                        serializer.Populate(subReader, dict);
            }
            else if (token.Type == JTokenType.Object)
            {
                using (var subReader = token.CreateReader())
                    serializer.Populate(subReader, dict);
    
            }
            return dict;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var dict = (IDictionary)value;
            // Prevent infinite recursion of converters by using DictionaryDTO
            serializer.Serialize(writer, dict.Select(p => new DictionaryDTO(p)));
        }
    }
    

    Then use it in your container class as follows:

    public class RootObject
    {
        [JsonProperty("value")]
        [JsonConverter(typeof(DictionaryToDictionaryListConverter))]
        public Dictionary Value { get; set; }
    }
    

    Note that the converter will throw an exception during reading if the keys are not unique.

    Update

    For AddressValue you could use the following converter:

    public class AddressValueConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(AddressValue);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var addressValue = (existingValue as AddressValue ?? new AddressValue());
            var token = JObject.Load(reader);
            var property = token.Properties().SingleOrDefault();
            if (property != null)
            {
                addressValue.Label = property.Name;
                addressValue.Value = (string)property.Value;
            }
            return addressValue;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var addressValue = (AddressValue)value;
            serializer.Serialize(writer, new Dictionary { { addressValue.Label, addressValue.Value } });
        }
    }
    

    Then use it as follows:

    [JsonConverter(typeof(AddressValueConverter))]
    public class AddressValue
    {
        public string Label { get; set; }
        public string Value { get; set; }
    }
    
    public class RootObject
    {
        [JsonProperty("value")]
        public List Value { get; set; }
    }
    

    Demo fiddle with both options here.

提交回复
热议问题