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

API-интерфейс LINQ-to-JSON ( 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; либо даст вам тот же результат.


Спасибо за продуманный ответ! Дескрипторы Object vs Dynamic теперь имеют смысл. Приведенный вами пример также великолепен - он выглядит намного проще, чем с JsonParseDynamic.
— Habatish 09

3
Я бы хотел, чтобы это было в официальных документах .
— Alex Angas

1
Является ли DeserializeObject толерантным к дополнительным свойствам в json, которых нет в классе. Будет ли он игнорировать их или генерировать исключение?
— Michael Freidgeim

1
@MichaelFreidgeim Это контролируется MissingMemberHandlingнастройкой. По умолчанию дополнительные свойства игнорируются.
— Брайан Роджерс

С точки зрения производительности, будет ли десериализация динамического объекта в среднем медленнее или быстрее, чем десериализация в строго типизированный класс? Я вижу разные причины того, что один быстрее другого, но мне интересно, может ли использование dynamic быть быстрее, потому что оно не должно использовать отражение?
— Dinerdo

27

JsonConvert.DeserializeObject имеет одно преимущество перед JObject.Parse: можно использовать настраиваемые параметры JsonSerializerSettings.

Это может быть очень полезно, например, если вы хотите контролировать десериализацию дат. По умолчанию даты десериализуются в объекты 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 может десериализовать 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 () can :)
— Frode Nilsen

1
@FrodeNilsen Кроме того, согласно моим тестам, JToken.Parse () оказался самым быстрым из всех методов динамической / десериализации на этой странице.
— Мейсон Г. Жвити

0

Помимо приведенных здесь ответов об использовании, которые, по моему Jobject.Parseмнению , верны: -> когда Json не сильно типизирован или вы не знаете структуру Json заранее

JsonConvert.DeserializeObject<T>-> Когда вы знаете, какой класс или тип использовать Json. TМожет быть сложным классом или простым типом

Мой ответ основан на производительности в случае, если структура неизвестна, как указано в коде OP, если мы протестируем использование обоих методов на производительность, наблюдается, что это Jobject.Parse()хорошо с точки зрения выделенной памяти, пожалуйста, игнорируйте имя методов, я сначала вызываю метод с помощью 'JsonConvert.DeserializeObject', а затем второй метод сJobject.Parse

введите описание изображения здесь

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.