web-dev-qa-db-ja.com

JObjectをDictionary <string、object>に変換します。出来ますか?

任意の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))
    )
)

ありがとう!

61
tucaz

最終的には両方の答えを混ぜて使用することになりました。

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ケースがあり、パフォーマンスが最強の品質ではない場合があります。

みんなありがとう!

22
tucaz

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);
108

開始バージョンは次のとおりです。コードを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;
    }
}
14
Uli

拡張メソッドの良いユースケースのように聞こえます-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}
        };
    }
}
3
JerKimball

より簡単なバージョンを次に示します。

    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;
    }
1