任意のjsonペイロードをJObject
プロパティに受け入れるWeb APIメソッドがあります。そのため、今後何が起こるのかわかりませんが、それを.NETタイプに変換する必要があります。 Dictionary<string,object>
が欲しいので、好きなように対処できます。
私は多くのことを検索しましたが、何も見つからず、この変換をキーごとに、値ごとに行うための厄介なメソッドを開始しました。それを行う簡単な方法はありますか?
入力->
JObject person = new JObject(
new JProperty("Name", "John Smith"),
new JProperty("BirthDate", new DateTime(1983, 3, 20)),
new JProperty("Hobbies", new JArray("Play football", "Programming")),
new JProperty("Extra", new JObject(
new JProperty("Foo", 1),
new JProperty("Bar", new JArray(1, 2, 3))
)
)
ありがとう!
最終的には両方の答えを混ぜて使用することになりました。
ToObject()は、JSONオブジェクトの最初のレベルのプロパティを実行できますが、ネストされたオブジェクトはDictionary()に変換されません。
ToObject()は第1レベルのプロパティで非常に優れているため、すべてを手動で行う必要もありません。
コードは次のとおりです。
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;
}
}
動作しないEdgeケースがあり、パフォーマンスが最強の品質ではない場合があります。
みんなありがとう!
JObject
オブジェクトがある場合、以下が機能する可能性があります。
JObject person;
var values = person.ToObject<Dictionary<string, object>>();
JObject
がない場合は、Newtonsoft.Json.Linq
拡張メソッドで作成できます:
using Newtonsoft.Json.Linq;
var values = JObject.FromObject(person).ToObject<Dictionary<string, object>>();
それ以外の場合、 この答え はJSON文字列をディクショナリにデシリアライズするため、正しい方向を示す場合があります。
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
開始バージョンは次のとおりです。コードをrecurse JArrays an JObjectsnested inJArrays/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;
}
}
拡張メソッドの良いユースケースのように聞こえます-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}
};
}
}
より簡単なバージョンを次に示します。
public static object ToCollections(object o)
{
var jo = o as JObject;
if (jo != null) return jo.ToObject<IDictionary<string, object>>().ToDictionary(k => k.Key, v => ToCollections(v.Value));
var ja = o as JArray;
if (ja != null) return ja.ToObject<List<object>>().Select(ToCollections).ToList();
return o;
}
C#7を使用している場合、次のようなパターンマッチングを使用できます。
public static object ToCollections(object o)
{
if (o is JObject jo) return jo.ToObject<IDictionary<string, object>>().ToDictionary(k => k.Key, v => ToCollections(v.Value));
if (o is JArray ja) return ja.ToObject<List<object>>().Select(ToCollections).ToList();
return o;
}