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();
        }
    }
}
Scott.Hu
источник
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

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

Раджив Сирохи
источник