JObject.Parse 대 JsonConvert.DeserializeObject


85

JsonConvert.DeserializeObject와 JObject.Parse의 차이점은 무엇입니까? 내가 말할 수있는 한, 둘 다 문자열을 취하고 Json.NET 라이브러리에 있습니다. 어떤 상황이 다른 것보다 더 편리할까요, 아니면 주로 선호하는 것입니까?

참고로 Json 문자열을 구문 분석하고 Json 속성 중 하나의 목록을 반환하기 위해 두 가지를 모두 사용하는 예가 있습니다.

public ActionResult ReadJson()
{
    string countiesJson = "{'Everything':[{'county_name':null,'description':null,'feat_class':'Civil','feature_id':'36865',"
                    +"'fips_class':'H1','fips_county_cd':'1','full_county_name':null,'link_title':null,'url':'http://www.alachuacounty.us/','name':'Alachua County'"+ ",'primary_latitude':'29.7','primary_longitude':'-82.33','state_abbreviation':'FL','state_name':'Florida'},"+
                    "{'county_name':null,'description':null,"+ "'feat_class':'Civil','feature_id':'36866','fips_class':'H1','fips_county_cd':'3','full_county_name':null,'link_title':null,'url':'http://www.bakercountyfl.org/','name':'Baker County','primary_latitude':'30.33','primary_longitude':'-82.29','state_abbreviation':'FL','state_name':'Florida'}]}";

    //Can use either JSONParseObject or JSONParseDynamic here
    List<string> counties = JSONParseObject(countiesJson);
    JSONParseDynamic(countiesJson);
    return View(counties);
}

public List<string> JSONParseObject(string jsonText)
{
    JObject jResults = JObject.Parse(jsonText);
    List<string> counties = new List<string>();
    foreach (var county in jResults["Everything"])
    {
        counties.Add((string)county["name"]);
    }
    return counties;
}

public List<string> JSONParseDynamic(string jsonText)
{
    dynamic jResults = JsonConvert.DeserializeObject(jsonText);
    List<string> counties = new List<string>();
    foreach(var county in jResults.Everything)
    {
        counties.Add((string)county.name);
    }
    return counties;
}

답변:


91

LINQ-to-JSON API ( JObject, JToken등)는 구조를 미리 알 필요없이 JSON으로 작업 할 수 있도록 존재합니다. 를 사용하여 임의의 JSON을 역 직렬화 JToken.Parse한 다음 다른 JToken메서드를 사용하여 해당 콘텐츠를 검사하고 조작 할 수 있습니다 . LINQ-to-JSON은 JSON에서 하나 또는 두 개의 값 (예 : 카운티 이름)이 필요한 경우에도 잘 작동합니다.

JsonConvert.DeserializeObject반면에는 주로 JSON의 구조를 미리 알고 있고 강력한 형식의 클래스로 역 직렬화하려는 경우에 주로 사용됩니다. 예를 들어 다음은 JSON에서 County개체 목록으로 전체 카운티 데이터 집합을 가져 오는 방법 입니다.

class Program
{
    static void Main(string[] args)
    {
        string countiesJson = "{'Everything':[{'county_name':null,'description':null,'feat_class':'Civil','feature_id':'36865',"
                +"'fips_class':'H1','fips_county_cd':'1','full_county_name':null,'link_title':null,'url':'http://www.alachuacounty.us/','name':'Alachua County'"+ ",'primary_latitude':'29.7','primary_longitude':'-82.33','state_abbreviation':'FL','state_name':'Florida'},"+
                "{'county_name':null,'description':null,"+ "'feat_class':'Civil','feature_id':'36866','fips_class':'H1','fips_county_cd':'3','full_county_name':null,'link_title':null,'url':'http://www.bakercountyfl.org/','name':'Baker County','primary_latitude':'30.33','primary_longitude':'-82.29','state_abbreviation':'FL','state_name':'Florida'}]}";

        foreach (County c in JsonParseCounties(countiesJson))
        {
            Console.WriteLine(string.Format("{0}, {1} ({2},{3})", c.name, 
               c.state_abbreviation, c.primary_latitude, c.primary_longitude));
        }
    }

    public static List<County> JsonParseCounties(string jsonText)
    {
        return JsonConvert.DeserializeObject<RootObject>(jsonText).Counties;
    }
}

public class RootObject
{
    [JsonProperty("Everything")]
    public List<County> Counties { get; set; }
}

public class County
{
    public string county_name { get; set; }
    public string description { get; set; }
    public string feat_class { get; set; }
    public string feature_id { get; set; }
    public string fips_class { get; set; }
    public string fips_county_cd { get; set; }
    public string full_county_name { get; set; }
    public string link_title { get; set; }
    public string url { get; set; }
    public string name { get; set; }
    public string primary_latitude { get; set; }
    public string primary_longitude { get; set; }
    public string state_abbreviation { get; set; }
    public string state_name { get; set; }
}

Json.Net은 JsonConvert.DeserializeObject생성 할 객체의 유형을 결정 하기 위해 메소드에 제공된 유형 인수 를 사용합니다.

당신이 호출 할 때 유형을 지정하지 않으면 물론, DeserializeObject또는 사용 object하거나 dynamic, 다음 Json.Net는로 역 직렬화 할 수밖에 없다 JObject. (확인을 통해 동적 변수가 실제로 a JObject를 보유하고 있음을 직접 확인할 수 있습니다 jResults.GetType().FullName.) 따라서이 경우 JsonConvert.DeserializeObject와 사이에는 큰 차이가 없습니다 JToken.Parse. 어느 쪽이든 동일한 결과를 제공합니다.


신중하게 답변 해 주셔서 감사합니다! 이제 개체 대 동적 설명자가 의미가 있습니다. 여러분이 제공하는 예제도 훌륭합니다. JsonParseDynamic을 사용하는 것보다 훨씬 쉬워 보입니다.
hubatish

3
나는 이것이 공식 문서 에 있었으면 좋겠다 .
Alex Angas

1
DeserializeObject는 클래스에없는 json의 추가 속성을 허용합니다. 무시하거나 예외를 던질까요?
Michael Freidgeim

1
@MichaelFreidgeim MissingMemberHandling설정에 의해 제어됩니다 . 기본값은 추가 속성을 무시하는 것입니다.
브라이언 로저스

성능 측면에서 동적 개체로의 역 직렬화가 강력한 형식의 클래스로 역 직렬화하는 것보다 평균적으로 더 느리거나 더 빠를까요? 하나가 다른 것보다 더 빠른 이유는 여러 가지가 있지만, 리플렉션을 사용할 필요가 없기 때문에 동적을 사용하는 것이 더 빠를 수 있는지 궁금합니다.
Dinerdo

27

JsonConvert.DeserializeObject는 JObject.Parse보다 한 가지 장점이 있습니다. 사용자 지정 JsonSerializerSettings를 사용할 수 있습니다.

이것은 날짜가 deserialize되는 방법을 제어하려는 경우에 매우 유용 할 수 있습니다. 기본적으로 날짜는 DateTime 개체로 역 직렬화됩니다. 즉, json 문자열의 시간대가 아닌 다른 시간대의 날짜로 끝날 수 있습니다.

JsonSerializerSetting을 만들고 DateParseHandling을 DateParseHandling.DateTimeOffset으로 설정하여이 동작을 변경할 수 있습니다.

예 :

var json = @"{ ""Time"": ""2015-10-28T14:05:22.0091621+00:00""}";
Console.WriteLine(json);
// Result: { "Time": "2015-10-28T14:05:22.0091621+00:00" }

var jObject1 = JObject.Parse(json);
Console.WriteLine(jObject1.ToString());
// Result: { "Time": "2015-10-28T15:05:22.0091621+01:00" }

var jObject2 = Newtonsoft.Json.JsonConvert.DeserializeObject(json, 
  new Newtonsoft.Json.JsonSerializerSettings 
  { 
    DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTimeOffset 
  });
Console.WriteLine(jObject2.ToString());
// Result: { "Time": "2015-10-28T14:05:22.0091621+00:00" }

어떤 클래스로 갈 것인지 (즉, 동적이 아닌) 정확히 알고 있다면 DeserializeObject를 사용하는 것이 더 빠르지 않습니까?
Dinerdo

0

JsonConvert.DeserializeObject가 Array / List json 텍스트를 직접 역 직렬화 할 수 있다는 이점을 알고 있었지만 JObject는 할 수 없습니다.

아래 샘플 코드를 시도하십시오.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

namespace NetCoreJsonNETDemo
{
    internal class Person
    {
        [JsonProperty]
        internal string Name
        {
            get;
            set;
        }

        [JsonProperty]
        internal int? Age
        {
            get;
            set;
        }
    }

    internal class PersonContainer
    {
        public List<Person> Persons
        {
            get;
            set;
        }
    }

    class Program
    {
        static T RecoverPersonsWithJsonConvert<T>(string json)
        {
            return JsonConvert.DeserializeObject<T>(json);
        }

        static T RecoverPersonsWithJObejct<T>(string json) where T : class
        {
            try
            {
                return JObject.Parse(json).ToObject<T>();
            }
            catch (Exception ex)
            {
                Console.WriteLine("JObject threw an Exception: " + ex.Message);
                return null;
            }
        }

        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();

            persons.Add(new Person()
            {
                Name = "Jack",
                Age = 18
            });

            persons.Add(new Person()
            {
                Name = "Sam",
                Age = null
            });

            persons.Add(new Person()
            {
                Name = "Bob",
                Age = 36
            });

            string json = JsonConvert.SerializeObject(persons, new JsonSerializerSettings()
            {
                Formatting = Formatting.Indented
            });

            List<Person> newPersons = RecoverPersonsWithJsonConvert<List<Person>>(json);
            newPersons = RecoverPersonsWithJObejct<List<Person>>(json);//JObject will throw an error, since the json text is an array.

            PersonContainer personContainer = new PersonContainer()
            {
                Persons = persons
            };

            json = JsonConvert.SerializeObject(personContainer, new JsonSerializerSettings()
            {
                Formatting = Formatting.Indented
            });

            newPersons = RecoverPersonsWithJObejct<PersonContainer>(json).Persons;

            newPersons = null;
            newPersons = RecoverPersonsWithJsonConvert<PersonContainer>(json).Persons;

            Console.WriteLine("Press any key to end...");
            Console.ReadKey();
        }
    }
}

1
JToken.Parse는 () :) 수 있습니다
프로드 닐슨에게

1
@FrodeNilsen 또한 JToken.Parse ()는 내 테스트에 따르면이 페이지의 모든 동적 / 역 직렬화 방법 중 가장 빠른 것으로 보입니다.
Mason G. Zhwiti

0

여기에 나와있는 사용법과 관련하여 제공되는 답변은 나에게 맞는 것입니다.- Jobject.Parse> Json이 강력하게 유형화되지 않았거나 Json의 구조를 미리 알지 못하는 경우

JsonConvert.DeserializeObject<T>-> Json을 캐스팅 할 클래스 또는 유형을 알고있는 T경우. 복합 클래스 또는 단순 유형일 수 있습니다 .

내 대답은 OP 코드에서와 같이 구조가 알려지지 않은 경우 성능을 기반으로 한 것입니다. 성능을 위해 두 방법의 사용을 벤치마킹하면 Jobject.Parse()할당 된 메모리 측면에서 요금이 잘되는 것으로 관찰 되므로 이름을 무시하십시오. 메서드 중 먼저 'JsonConvert.DeserializeObject'로 메서드를 호출하고 두 번째 메서드는Jobject.Parse

여기에 이미지 설명 입력

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.