Преобразование JObject в словарь <string, object>. Является ли это возможным?
У меня есть метод web api, который принимает произвольную полезную нагрузку json в свойство JObject. Поэтому я не знаю, что произойдет, но мне все равно нужно перевести его на типы .NET. Я хотел бы иметь словарь, чтобы я мог справиться с ним, в любом случае, я хочу.
Я много искал, но ничего не мог найти и закончил тем, что начал беспорядочный метод для этого преобразования, ключ от ключа, значение по значению. Есть ли простой способ сделать это?
Вход →
JObject person = new JObject(
new JProperty("Name", "John Smith"),
new JProperty("BirthDate", new DateTime(1983, 3, 20)),
new JProperty("Hobbies", new JArray("Play footbal", "Programming")),
new JProperty("Extra", new JObject(
new JProperty("Foo", 1),
new JProperty("Bar", new JArray(1, 2, 3))
)
)
Спасибо!
Ответы
Ответ 1
В итоге я использовал сочетание обоих ответов, так как никто не прибил его.
ToObject() может выполнять первый уровень свойств в объекте JSON, но вложенные объекты не будут преобразованы в Dictionary().
Также нет необходимости делать все вручную, так как ToObject() очень хорош с свойствами первого уровня.
Вот код:
public static class JObjectExtensions
{
public static IDictionary<string, object> ToDictionary(this JObject @object)
{
var result = @object.ToObject<Dictionary<string, object>>();
var JObjectKeys = (from r in result
let key = r.Key
let value = r.Value
where value.GetType() == typeof(JObject)
select key).ToList();
var JArrayKeys = (from r in result
let key = r.Key
let value = r.Value
where value.GetType() == typeof(JArray)
select key).ToList();
JArrayKeys.ForEach(key => result[key] = ((JArray)result[key]).Values().Select(x => ((JValue)x).Value).ToArray());
JObjectKeys.ForEach(key => result[key] = ToDictionary(result[key] as JObject));
return result;
}
}
У этого могут быть краевые случаи, когда он не будет работать, а производительность не является самым сильным его качеством.
Спасибо, ребята!
Ответ 2
Если у вас есть объекты JObject
, может работать следующее:
JObject person;
var values = person.ToObject<Dictionary<string, object>>();
В противном случае этот ответ может указывать на вас в правильном направлении, поскольку он десериализует строку JSON в словаре.
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
Ответ 3
Здесь начальная версия: я изменил код на recurse JArrays JObjects, вложенные в JArrays/JObjects, что принятый ответ не указан, как указано @Nawaz.
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
public static class JsonConversionExtensions
{
public static IDictionary<string, object> ToDictionary(this JObject json)
{
var propertyValuePairs = json.ToObject<Dictionary<string, object>>();
ProcessJObjectProperties(propertyValuePairs);
ProcessJArrayProperties(propertyValuePairs);
return propertyValuePairs;
}
private static void ProcessJObjectProperties(IDictionary<string, object> propertyValuePairs)
{
var objectPropertyNames = (from property in propertyValuePairs
let propertyName = property.Key
let value = property.Value
where value is JObject
select propertyName).ToList();
objectPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToDictionary((JObject) propertyValuePairs[propertyName]));
}
private static void ProcessJArrayProperties(IDictionary<string, object> propertyValuePairs)
{
var arrayPropertyNames = (from property in propertyValuePairs
let propertyName = property.Key
let value = property.Value
where value is JArray
select propertyName).ToList();
arrayPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToArray((JArray) propertyValuePairs[propertyName]));
}
public static object[] ToArray(this JArray array)
{
return array.ToObject<object[]>().Select(ProcessArrayEntry).ToArray();
}
private static object ProcessArrayEntry(object value)
{
if (value is JObject)
{
return ToDictionary((JObject) value);
}
if (value is JArray)
{
return ToArray((JArray) value);
}
return value;
}
}
Ответ 4
Звучит как хороший вариант использования для методов расширения - у меня было что-то лежащее, что было довольно просто преобразовать в Json.NET(спасибо NuGet!):
Конечно, это быстро взломано - вы хотите очистить его и т.д.
public static class JTokenExt
{
public static Dictionary<string, object>
Bagify(this JToken obj, string name = null)
{
name = name ?? "obj";
if(obj is JObject)
{
var asBag =
from prop in (obj as JObject).Properties()
let propName = prop.Name
let propValue = prop.Value is JValue
? new Dictionary<string,object>()
{
{prop.Name, prop.Value}
}
: prop.Value.Bagify(prop.Name)
select new KeyValuePair<string, object>(propName, propValue);
return asBag.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
if(obj is JArray)
{
var vals = (obj as JArray).Values();
var alldicts = vals
.SelectMany(val => val.Bagify(name))
.Select(x => x.Value)
.ToArray();
return new Dictionary<string,object>()
{
{name, (object)alldicts}
};
}
if(obj is JValue)
{
return new Dictionary<string,object>()
{
{name, (obj as JValue)}
};
}
return new Dictionary<string,object>()
{
{name, null}
};
}
}