sourcecode

JObject를 사전으로 변환합니다. 가능합니까?

codebag 2023. 2. 7. 19:52
반응형

JObject를 사전으로 변환합니다. 가능합니까?

임의의 json payload를 받아들인 웹 API 메서드가 있습니다.JObject소유물.그래서 뭐가 올지 모르겠지만 로 번역해야 합니다.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))
    )
)

감사합니다!

가지고 계신 경우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);

어느 누구도 정확히 들어맞지 못했기 때문에 나는 결국 두 가지 답을 혼합해서 사용했다.

ToObject()는 JSON 개체의 첫 번째 수준의 속성을 수행할 수 있지만 중첩된 개체는 사전()으로 변환되지 않습니다.

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

동작하지 않는 엣지 케이스와 퍼포먼스가 최강의 품질이 아닐 수 있습니다.

감사합니다 여러분!

JArays/JObjects중첩된 JArrays재현하기 위해 코드를 수정했지만, @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;
    }
}

다음은 간단한 버전입니다.

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

확장 방법의 좋은 사용 사례로 들리네요.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}
        };
    }
}

언급URL : https://stackoverflow.com/questions/14886800/convert-jobject-into-dictionarystring-object-is-it-possible

반응형