{ "rates_scores_stats": [{ "name": 10, "value": 3545 }, { "name": 9, "value": 1004 }, { "name": 8, "value": 820 }, { "name": 7, "value": 493 }, { "name": 6, "value": 218 }, { "name": 5, "value": 138 }, { "name": 4, "value": 80 }, { "name": 3, "value": 41 }, { "name": 2, "value": 26 }, { "name": 1, "value": 83 } ], "rates_statuses_stats": [{ "name": "Запланировано", "value": 2506 }, { "name": "Смотрю", "value": 7861 }, { "name": "Просмотрено", "value": 1947 }, { "name": "Отложено", "value": 1443 }, { "name": "Брошено", "value": 1358 } ] } 

There is a JSON described above. For deserialization, I use Newtonsoft.Json. In particular, the method JsonConvert.DeserializeObject (json)

I know that for this json you can describe a typical class like this.

An example of a working class for deserialization

Same text: http://pastexen.com/code.php?file=aMvORa6As3.cs

But I need to turn it into a collection of auxiliary classes or a collection of KeyValuePair. I need a dictionary so that I can refer to such an object as follows:

 var result = JsonConvert.DeserializeObject<MyClass>(json); var val = result.rates_scores_stats[10]; // val = 3545 var val1 = result.rates_statuses_stats["Смотрю"]; // val1 = 7861 

Is it possible to serialize it somehow into the dictionary? Can using get / set somehow dodge?

PS: I know that in Sharp there is Linq, which will allow you to do something like result.FirstOrDefault (x.value => x.name == "10") , but I am writing a portable library and want to simplify data access = /

  • Newtonsoft.Json has the opportunity to work from json via LINQ - Bulson
  • @Bulson and more? - MrModest

1 answer 1

For example, you can deserialize into JObject , and then convert the data manually:

 var obj = JObject.Parse(json); var rates_scores_stats = ((JArray)obj["rates_scores_stats"]).ToDictionary(entry => (int)entry["name"], entry => (int)entry["value"]); var rates_statuses_stats = ((JArray)obj["rates_statuses_stats"]).ToDictionary(entry => (string)entry["name"], entry => (int)entry["value"]); var result = new MyClass() { rates_scores_stats = rates_scores_stats, rates_statuses_stats = rates_statuses_stats }; 

The alternative answer is here . By slightly modifying it, you can get a less “manual” solution.

Create a separate converter (damned and modified from the response by reference):

 public class JsonGenericDictionaryOrArrayConverter : JsonConverter { // поскольку у вас в JSON'е не key/value, а name/value, нужен специальный класс // для десериализации одного элемента массива class NameValuePair<N, V> { public N name { get; set; } public V value { get; set; } } public override bool CanConvert(Type objectType) { return GetDictionaryKeyValueTypes(objectType).Count() == 1; } public override bool CanWrite { get { return false; } } object ReadJsonGeneric<TKey, TValue>( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var tokenType = reader.TokenType; var dict = existingValue as IDictionary<TKey, TValue>; if (dict == null) { var contract = serializer.ContractResolver.ResolveContract(objectType); dict = (IDictionary<TKey, TValue>)contract.DefaultCreator(); } if (tokenType == JsonToken.StartArray) { var pairs = new JsonSerializer() .Deserialize<NameValuePair<TKey, TValue>[]>(reader); if (pairs == null) return existingValue; foreach (var pair in pairs) dict.Add(pair.name, pair.value); } else if (tokenType == JsonToken.StartObject) { // Using "Populate()" avoids infinite recursion. // https://github.com/JamesNK/Newtonsoft.Json/blob/ // ee170dc5510bb3ffd35fc1b0d986f34e33c51ab9/Src/Newtonsoft.Json/Converters/ // CustomCreationConverter.cs serializer.Populate(reader, dict); } return dict; } public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // Throws an exception if not exactly one. var keyValueTypes = GetDictionaryKeyValueTypes(objectType).Single(); var method = GetType().GetMethod( "ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); var genericMethod = method.MakeGenericMethod( new[] { keyValueTypes.Key, keyValueTypes.Value }); return genericMethod.Invoke( this, new object[] { reader, objectType, existingValue, serializer }); } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer) { throw new NotSupportedException(); } static IEnumerable<KeyValuePair<Type, Type>> GetDictionaryKeyValueTypes(Type type) { foreach (Type intType in GetInterfacesAndSelf(type)) { if (intType.IsGenericType && intType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) { var args = intType.GetGenericArguments(); if (args.Length == 2) yield return new KeyValuePair<Type, Type>(args[0], args[1]); } } } static IEnumerable<Type> GetInterfacesAndSelf(Type type) { if (type == null) throw new ArgumentNullException(); if (type.IsInterface) return new[] { type }.Concat(type.GetInterfaces()); else return type.GetInterfaces(); } } 

Having this auxiliary class, you can deserialize just like this:

 var settings = new JsonSerializerSettings { Converters = { new JsonGenericDictionaryOrArrayConverter() } }; var result = JsonConvert.DeserializeObject<MyClass>(jsonString, settings); 

Update: For a portable library (.NET 4.5.1 + Windows Universal 8.1 + Windows Phone 8.1) I have compiled this:

 public class JsonGenericDictionaryOrArrayConverter : JsonConverter { // поскольку у вас в JSON'е не key/value, а name/value, нужен специальный класс // для десериализации одного элемента массива class NameValuePair<N, V> { public N name { get; set; } public V value { get; set; } } public override bool CanConvert(Type objectType) { return GetDictionaryKeyValueTypes(objectType).Count() == 1; } public override bool CanWrite { get { return false; } } public object ReadJsonGeneric<TKey, TValue>( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var tokenType = reader.TokenType; var dict = existingValue as IDictionary<TKey, TValue>; if (dict == null) { var contract = serializer.ContractResolver.ResolveContract(objectType); dict = (IDictionary<TKey, TValue>)contract.DefaultCreator(); } if (tokenType == JsonToken.StartArray) { var pairs = new JsonSerializer() .Deserialize<NameValuePair<TKey, TValue>[]>(reader); if (pairs == null) return existingValue; foreach (var pair in pairs) dict.Add(pair.name, pair.value); } else if (tokenType == JsonToken.StartObject) { // Using "Populate()" avoids infinite recursion. // https://github.com/JamesNK/Newtonsoft.Json/blob/ // ee170dc5510bb3ffd35fc1b0d986f34e33c51ab9/Src/Newtonsoft.Json/Converters/ // CustomCreationConverter.cs serializer.Populate(reader, dict); } return dict; } public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // Throws an exception if not exactly one. var keyValueTypes = GetDictionaryKeyValueTypes(objectType).Single(); var method = GetType().GetTypeInfo().GetDeclaredMethod("ReadJsonGeneric"); var genericMethod = method.MakeGenericMethod( new[] { keyValueTypes.Key, keyValueTypes.Value }); return genericMethod.Invoke( this, new object[] { reader, objectType, existingValue, serializer }); } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer) { throw new NotSupportedException(); } static IEnumerable<KeyValuePair<Type, Type>> GetDictionaryKeyValueTypes(Type type) { foreach (Type intType in GetInterfacesAndSelf(type)) { if (intType.GetTypeInfo().IsGenericType && intType.GetGenericTypeDefinition() == typeof(IDictionary<,>)) { var args = intType.GetTypeInfo().GenericTypeArguments; // вроде бы именно GenericTypeArguments, а не Parameters if (args.Length == 2) yield return new KeyValuePair<Type, Type>(args[0], args[1]); } } } static IEnumerable<Type> GetInterfacesAndSelf(Type type) { if (type == null) throw new ArgumentNullException(); if (type.GetTypeInfo().IsInterface) return new[] { type }.Concat(type.GetTypeInfo().ImplementedInterfaces); else return type.GetTypeInfo().ImplementedInterfaces; } } 
  • Comments are not intended for extended discussion; conversation moved to chat . - Nofate