JObject.Parse与JsonConvert.DeserializeObject


83

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

Answers:


89

存在LINQ-to-JSON API(JObjectJToken等)可以使用JSON,而无需提前知道其结构。您可以使用来反序列化任意JSON JToken.Parse,然后使用其他JToken方法检查并处理其内容。如果您只需要JSON中的一个或两个值(例如县名),则LINQ-to-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方法的type参数来确定要创建的对象类型。

当然,如果您在调用时未指定类型DeserializeObject,或者使用objectdynamic,则Json.Net只能选择反序列化为JObject。(您可以JObject通过检查自己看到您的动态变量实际上持有a jResults.GetType().FullName。)因此,在这种情况下,JsonConvert.DeserializeObject和之间没有太大区别JToken.Parse。两者都会给您相同的结果。


感谢深思熟虑的答案!对象与动态描述符现在很有意义。您提供的示例也很棒-看起来比使用JsonParseDynamic容易得多。
2014年

3
我希望这是在官方文档中
亚历克斯·安加斯

1
DeserializeObject可以容忍json中的额外属性,这些属性在类中不存在。它会忽略它们还是抛出异常?
Michael Freidgeim

1
@MichaelFreidgeim由MissingMemberHandling设置控制。默认值为忽略其他属性。
Brian Rogers

在性能方面,平均而言,反序列化到动态对象要比反序列化到强类型类慢还是快?我可以看到一个原因要比另一个更快的不同原因,但是我想知道使用动态是否会更快,因为它不必使用反射?
Dinerdo

27

与JObject.Parse相比,JsonConvert.DeserializeObject具有一个优点:可以使用自定义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可以直接反序列化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()可以:)
Frode Nilsen

1
@FrodeNilsen另外,根据我的测试,JToken.Parse()似乎是此页面上所有动态/反序列化方法中最快的。
Mason G. Zhwiti

0

除了此处提供的有关用法的答案外,按照我Jobject.Parse的说法是正确的: ->当Json的类型不是强类型时,或者您事先不知道Json的结构时

JsonConvert.DeserializeObject<T>->当您知道要转换Json的类或类型时,T可以是复杂的类或简单的类型

我的答案基于OP代码中给出的未知结构的性能,如果我们对这两种方法的性能进行基准测试,可以发现Jobject.Parse()在分配的内存方面表现良好,请忽略名称在方法中,我首先使用“ JsonConvert.DeserializeObject”调用该方法,然后使用Jobject.Parse

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.