JObject.Parse so với JsonConvert.DeserializeObject


83

Sự khác biệt giữa JsonConvert.DeserializeObject và JObject.Parse là gì? Theo như tôi có thể nói, cả hai đều lấy một chuỗi và nằm trong thư viện Json.NET. Tình huống nào sẽ làm cho cái này thuận tiện hơn cái kia, hay chủ yếu chỉ là sở thích?

Để tham khảo, đây là một ví dụ về việc tôi sử dụng cả hai để thực hiện chính xác cùng một việc - phân tích cú pháp chuỗi Json và trả về danh sách một trong các thuộc tính 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;
}

Câu trả lời:


89

API LINQ-to-JSON ( JObject, JTokenv.v.) tồn tại để cho phép làm việc với JSON mà không cần biết trước cấu trúc của nó. Bạn có thể giải mã hóa bất kỳ JSON tùy ý nào bằng cách sử dụng JToken.Parse, sau đó kiểm tra và thao tác nội dung của nó bằng các JTokenphương pháp khác . LINQ-to-JSON cũng hoạt động tốt nếu bạn chỉ cần một hoặc hai giá trị từ JSON (chẳng hạn như tên của một quận).

JsonConvert.DeserializeObjectmặt khác, nó chủ yếu được sử dụng khi bạn biết trước cấu trúc của JSON và bạn muốn deserialize thành các lớp được đánh máy mạnh. Ví dụ: đây là cách bạn lấy toàn bộ dữ liệu hạt từ JSON của mình vào danh sách các Countyđối tượng.

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

Lưu ý rằng Json.Net sử dụng đối số kiểu được cung cấp cho JsonConvert.DeserializeObjectphương thức để xác định kiểu đối tượng cần tạo.

Tất nhiên, nếu bạn không chỉ định một kiểu khi bạn gọi DeserializeObject, hoặc bạn sử dụng objecthoặc dynamic, thì Json.Net không có lựa chọn nào khác ngoài việc deserialize thành a JObject. (Bạn có thể tự mình thấy rằng biến động của bạn thực sự giữ a JObjectbằng cách kiểm tra jResults.GetType().FullName.) Vì vậy, trong trường hợp đó, không có nhiều sự khác biệt giữa JsonConvert.DeserializeObjectJToken.Parse; hoặc sẽ cho bạn kết quả tương tự.


Cảm ơn vì câu trả lời thấu đáo! Các bộ mô tả Đối tượng và Động có ý nghĩa ngay bây giờ. Ví dụ bạn đưa ra cũng rất tuyệt - trông dễ dàng hơn nhiều so với với JsonParseDynamic.
hubatish

3
Tôi ước điều này có trong tài liệu chính thức .
Alex Angas

1
DeserializeObject có dung nạp các thuộc tính bổ sung trong json không, không tồn tại trong lớp. Nó sẽ bỏ qua chúng hoặc ném ngoại lệ?
Michael Freidgeim

1
@MichaelFreidgeim Nó được kiểm soát bởi MissingMemberHandlingcài đặt. Mặc định là bỏ qua các thuộc tính bổ sung.
Brian Rogers

Về mặt hiệu suất, trung bình việc giải kích thước đối với một đối tượng động sẽ chậm hơn hoặc nhanh hơn so với giải kích thước đối với một lớp được đánh mạnh? Tôi có thể thấy các lý do khác nhau khiến cái này nhanh hơn cái kia, nhưng tôi tự hỏi liệu sử dụng động có thể nhanh hơn vì nó không phải sử dụng phản xạ không?
Dinerdo

27

JsonConvert.DeserializeObject có một lợi thế hơn JObject.Parse: Có thể sử dụng JsonSerializerSettings tùy chỉnh.

Điều này có thể rất hữu ích, ví dụ như nếu bạn muốn kiểm soát cách ngày tháng được gỡ bỏ. Theo mặc định, ngày tháng được deserialized thành các đối tượng DateTime. Điều này có nghĩa là bạn có thể kết thúc với một ngày có múi giờ khác với múi giờ trong chuỗi json.

Bạn có thể thay đổi hành vi này bằng cách tạo một JsonSerializerSetting và đặt DateParseHandling thành DateParseHandling.DateTimeOffset.

Một ví dụ:

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

Việc sử dụng DeserializeObject cũng không nhanh hơn nếu bạn biết chính xác lớp mình sắp học (tức là không động)?
Dinerdo

0

Tôi biết một ưu điểm là JsonConvert.DeserializeObject có thể giải mã trực tiếp một văn bản json Array / List , nhưng JObject thì không.

Hãy thử mã mẫu dưới đây:

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 () có thể :)
Frode Nilsen

1
@FrodeNilsen Ngoài ra, JToken.Parse () dường như là nhanh nhất trong số tất cả các phương pháp động / giải hóa trên trang này, theo thử nghiệm của tôi.
Mason G. Zhwiti

0

Ngoài các câu trả lời được cung cấp ở đây về cách sử dụng, theo tôi là đúng: Jobject.Parse-> khi Json không được gõ mạnh hoặc bạn không biết cấu trúc của Json trước thời hạn

JsonConvert.DeserializeObject<T>-> Khi bạn biết lớp hoặc kiểu nào để truyền Json vào. TCó thể là một lớp phức tạp hoặc một kiểu đơn giản

Câu trả lời của tôi dựa trên hiệu suất trong trường hợp không xác định được cấu trúc, như đã cho trong mã OP, nếu chúng tôi đánh giá việc sử dụng cả hai phương pháp cho hiệu suất, có thể thấy rằng Jobject.Parse()giá vé tốt về bộ nhớ được cấp phát, vui lòng bỏ qua tên trong số các phương thức, đầu tiên tôi gọi phương thức với 'JsonConvert.DeserializeObject' và sau đó phương thức thứ hai là vớiJobject.Parse

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.