K
For example, you can disserialyze http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JObject.htm and then scoop 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
};
Alternative response https://stackoverflow.com/a/28633769/276994 ♪ A slightly modified solution can be obtained with less " manual " .Create a separate converter.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();
}
}
If you have this auxiliary class, you can desserialyise just like this:var settings = new JsonSerializerSettings
{
Converters = { new JsonGenericDictionaryOrArrayConverter() }
};
var result = JsonConvert.DeserializeObject<MyClass>(jsonString, settings);
Update: For portable library (.NET 4.5.1 + Windows Universal 8.1 + Windows Phone 8.1), I have been computed with: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;
}
}