JObject.ParseとJsonConvert.DeserializeObject


83

JsonConvert.DeserializeObjectとJObject.Parseの違いは何ですか?私の知る限り、どちらも文字列を取り、Json.NETライブラリにあります。どのような状況が一方を他方よりも便利にするのでしょうか、それとも主に好みですか?

参考までに、両方を使用してまったく同じことを行う例を次に示します。Json文字列を解析し、Json属性の1つのリストを返します。

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

回答:


89

LINQ-to-JSON API(JObjectJTokenなど)は、JSONの構造を事前に知る必要なしにJSONを操作できるようにするために存在します。を使用して任意のJSONを逆シリアル化しJToken.Parse、他のJToken方法を使用してその内容を調べて操作できます。LINQ-to-JSONは、JSONから1つまたは2つの値(郡の名前など)が必要な場合にも適切に機能します。

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、またはまたはを使用するobject場合dynamic、Json.Netはにデシ​​リアライズする以外に選択肢はありませんJObject。(JObjectチェックすることで、動的変数が実際にを保持していることがわかりますjResults.GetType().FullName。)したがって、その場合、JsonConvert.DeserializeObjectJToken.Parse;の間に大きな違いはありません。どちらでも同じ結果が得られます。


よく考えられた答えをありがとう!オブジェクトと動的記述子は今では意味があります。あなたが与える例も素晴らしいです-それはJsonParseDynamicの場合よりもはるかに簡単に見えます。
騒々しい2014

3
これが公式ドキュメントにあったらいいのにと思います。
Alex Angas 2016年

1
DeserializeObjectは、クラスに存在しないjsonの追加のプロパティに耐性があります。それらを無視しますか、それとも例外をスローしますか?
Michael Freidgeim 2016

1
@MichaelFreidgeimMissingMemberHandling設定によって制御されます。デフォルトでは、余分なプロパティは無視されます。
ブライアンロジャース

パフォーマンス面では、動的オブジェクトへの逆シリアル化は、強く型付けされたクラスへの逆シリアル化よりも、平均して遅くなるのでしょうか、それとも速くなるのでしょうか。一方が他方よりも速い理由はさまざまですが、リフレクションを使用する必要がないため、ダイナミックを使用する方が速いのではないかと思います。
Dinerdo 2017年

27

JsonConvert.DeserializeObjectには、JObject.Parseに比べて1つの利点があります。カスタムの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を使用する方が速いのではないでしょうか。
ディネルド2018年

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()は:)
Frode Nilsen

1
@FrodeNilsenまた、私のテストによると、JToken.Parse()は、このページのすべての動的/逆シリアル化メソッドの中で最速のようです。
メイソンG.ズウィティ

0

ここで提供されている使用法に関する回答は別として、私によれば正しいです: Jobject.Parse-> Jsonが強く型付けされていない場合、またはJsonの構造が事前にわからない場合

JsonConvert.DeserializeObject<T>-> Jsonをキャストするクラスまたは型がわかっている場合はT、複雑なクラスまたは単純な型にすることができます

私の答えは、OPコードに示されているように、構造が不明な場合のパフォーマンスに基づいています。パフォーマンスについて両方の方法の使用をベンチマークするとJobject.Parse()、割り当てられたメモリの点でうまくいくことが観察されます。名前は無視してください。メソッドの中で、私は最初に「JsonConvert.DeserializeObject」でメソッドを呼び出し、次に2番目のメソッドでJobject.Parse

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.