Newtonsoft JSON.NET解析为自定义键/值对对象的数组(Newtonsoft JSON.NET parse to array of custom key/value pair objec

编程入门 行业动态 更新时间:2024-10-05 17:28:26
Newtonsoft JSON.NET解析为自定义键/值对对象的数组(Newtonsoft JSON.NET parse to array of custom key/value pair objects)

解析给定的JSON数据时,我遇到了这个奇怪的问题。 我有这个JSON结构:

{"value":[ {"street":"Karlova 25"}, {"city":"Prague"}, {"gpsLat":"50.1571"}, {"gpsLon":"15.0482"} ]}

如何使用Newtonsoft JSON.NET库解析这个结构? 我试图使用自己的JsonConverter类:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){ JArray jarray = (JArray)((JTokenReader)reader).CurrentToken; List<AddressValue> values = new List<AddressValue>(); foreach (var jobj in jarray.Children<JObject>()){ foreach (JProperty prop in jobj.Properties()){ values.Add(new AddressValue() { Label = prop.Name, Value = prop.Value.ToString() }); } } return values.ToArray(); } class AddressValue{ public string Label { get; set; } public string Value { get; set; } }

但我有一个例外:

Exception thrown: 'Newtonsoft.Json.JsonSerializationException' in Newtonsoft.Json.DLL Additional information: Unexpected token when deserializing object: StartObject. Path 'value[0]'.

编辑:我也尝试将其保存到词典:

[JsonProperty(PropertyName = "value")] public Dictionary<string, string> Value{get; set;}

但我有另一个例外:

$exception {"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.String]' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath 'param.value'."}

我做错了什么? 谢谢您的回答。

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

{"value":[ {"street":"Karlova 25"}, {"city":"Prague"}, {"gpsLat":"50.1571"}, {"gpsLon":"15.0482"} ]}

How to parse this structure using Newtonsoft JSON.NET library? I tried to use my own JsonConverter class:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){ JArray jarray = (JArray)((JTokenReader)reader).CurrentToken; List<AddressValue> values = new List<AddressValue>(); foreach (var jobj in jarray.Children<JObject>()){ foreach (JProperty prop in jobj.Properties()){ values.Add(new AddressValue() { Label = prop.Name, Value = prop.Value.ToString() }); } } return values.ToArray(); } class AddressValue{ public string Label { get; set; } public string Value { get; set; } }

but I have got an exception:

Exception thrown: 'Newtonsoft.Json.JsonSerializationException' in Newtonsoft.Json.DLL Additional information: Unexpected token when deserializing object: StartObject. Path 'value[0]'.

EDIT: I also tried to save this to Dictionary:

[JsonProperty(PropertyName = "value")] public Dictionary<string, string> Value{get; set;}

But I have another exception:

$exception {"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.String]' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath 'param.value'."}

What I am doing wrong? Thank you for your answers.

最满意答案

您似乎希望在JSON中将Dictionary<string, string>表示为对象数组,其中每个嵌套对象都有一个键和字典值。 您可以使用以下转换器执行此操作:

public class DictionaryToDictionaryListConverter<TKey, TValue> : JsonConverter { [ThreadStatic] static bool disabled; // Disables the converter in a thread-safe manner. bool Disabled { get { return disabled; } set { disabled = value; } } public override bool CanWrite { get { return !Disabled; } } public override bool CanRead { get { return !Disabled; } } public override bool CanConvert(Type objectType) { if (Disabled) return false; return typeof(IDictionary<TKey, TValue>).IsAssignableFrom(objectType); } 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<TKey, TValue>)(existingValue as IDictionary<TKey, TValue> ?? 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<TKey, TValue>)value; // Prevent infinite recursion of converters using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) { serializer.Serialize(writer, dict.Select(p => new[] { p }.ToDictionary(p2 => p2.Key, p2 => p2.Value))); } } } public struct PushValue<T> : IDisposable { Action<T> setValue; T oldValue; public PushValue(T value, Func<T> getValue, Action<T> setValue) { if (getValue == null || setValue == null) throw new ArgumentNullException(); this.setValue = setValue; this.oldValue = getValue(); setValue(value); } // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class. public void Dispose() { if (setValue != null) setValue(oldValue); } }

然后在容器类中使用它,如下所示:

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

请注意,如果键不是唯一的,转换器将在读取期间抛出异常。

更新

对于AddressValue您可以使用以下转换器:

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<string, string> { { addressValue.Label, addressValue.Value } }); } }

然后使用如下:

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

It appears that you want to represent a Dictionary<string, string> 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<TKey, TValue> : JsonConverter { class DictionaryDTO : Dictionary<TKey, TValue> { public DictionaryDTO(KeyValuePair<TKey, TValue> pair) : base(1) { Add(pair.Key, pair.Value); } } public override bool CanConvert(Type objectType) { return typeof(IDictionary<TKey, TValue>).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<TKey, TValue>)(existingValue as IDictionary<TKey, TValue> ?? 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<TKey, TValue>)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<string, string>))] public Dictionary<string, string> 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<string, string> { { 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<AddressValue> Value { get; set; } }

Demo fiddle with both options here.

更多推荐

本文发布于:2023-08-07 12:43:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1464113.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   数组   对象   NET   Newtonsoft

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!