JObject.Parse проти JsonConvert.DeserializeObject


84

Яка різниця між 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;
}

Відповіді:


90

Існує 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.DeserializeObjectand немає великої різниці JToken.Parse; або дасть вам однаковий результат.


Дякуємо за продуману відповідь! Дескриптори Object vs Dynamic мають сенс зараз. Приклад, який ви наводите, також чудовий - це виглядає набагато простіше, ніж було б з JsonParseDynamic.
hubatish

3
Я хотів би, щоб це було в офіційних документах .
Alex Angas

1
Чи толерантний DeserializeObject до додаткових властивостей у json, які не існують у класі. Це буде їх ігнорувати чи викидати виняток?
Michael Freidgeim

1
@MichaelFreidgeim Це контролюється MissingMemberHandlingналаштуванням. За замовчуванням ігнорувати зайві властивості.
Брайан Роджерс

З точки зору продуктивності, чи десериалізація динамічного об’єкта в середньому буде повільнішою чи швидшою, ніж десеріалізація його до сильно набраного класу? Я бачу різні причини того, що одна з них швидша, ніж інша, але мені цікаво, чи може використання динаміки бути швидшою, оскільки вона не повинна використовувати відображення?
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.