[C#] C#でJSONを扱う方法まとめ

csharp

はじめに

こんにちは!モバイルアプリサービス部の加藤です。
今回はC#でJSONを扱う方法について書いてみたいと思います。 C#でJSONを扱う方法はいろいろありますが、

  • DataContractJsonSerializer
  • Json.NET
  • DynamicJson

あたりがよく知られたメジャーな方法だと思いますので、これらについてまとめてみたいと思います。

開発環境

  • Visual Studio for Mac Preview 1(7.0 build 347)
  • .NETコンソールプロジェクト
  • ターゲットフレームワーク Mono / .NET 4.5

DataContractJsonSerializer

DataContractJsonSerializerとは

.NET Frameworkで提供されている、オブジェクトをJSONにシリアライズ、JSONをオブジェクトにデシリアライズするためのクラスです。 名前空間はSystem.Runtime.Serialization.Json、アセンブリはSystem.Runtime.Serialization.dllです。

参照を追加する

DataContractJsonSerializerを使うにはアセンブリの参照を追加する必要があります。

プロジェクトの「参照」を右クリックして「参照の編集」をクリックします。 参照の編集

「System.Runtime.Serialization」で検索し、アセンブリSystem.Runtime.SerializationにチェックをつけてOKをクリックします。 System_Runtime_Serialization

また、アセンブリSystem.Xmlも必要になるので同様に追加しておきます。 System_Xml

オブジェクトをJSONにシリアライズ

以下のようなモデルクラスをJSONにシリアライズする場合を考えます。

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

以下のusingを追加し、

using System.Runtime.Serialization.Json;
using System.IO;
using static System.Console;

シリアライズは以下のように行います。

var p = new Person();
p.Name = "Kato Jun";
p.Age = 31;

using (var ms = new MemoryStream())
using (var sr = new StreamReader(ms))
{
    var serializer = new DataContractJsonSerializer(typeof(Person));
    serializer.WriteObject(ms, p);
    ms.Position = 0;

    var json = sr.ReadToEnd();

    WriteLine($"{json}"); // {"Age":31,"Name":"Kato Jun"}
}

DataMember属性でJSONのキーを指定する

上述の例ではモデルクラスのプロパティ名がそのままJSONのキーになっており、先頭が大文字になっています。 先頭を小文字にしたい場合やプロパティ名とは別のキーを指定したい場合はDataMember属性を使用します。以下のようにクラスにDataContract属性、プロパティにDataMember属性を付与し、NameにJSONのキーを指定します。

// DataContractやDataMemberを使うために必要
using System.Runtime.Serialization;

[DataContract]
public class Person
{
    [DataMember(Name="name")]
    public string Name { get; set; }

    [DataMember(Name = "age")]
    public int Age { get; set; }
}

シリアライズ結果は以下のようになります。

{"age":31,"name":"Kato Jun"}

IgnoreDataMember属性でシリアライズ対象外を設定する

上述した例ではモデルクラスに定義したプロパティ全てをJSONにシリアライズしましたが、ケースによってはJSONに含めたくないプロパティも出てきます。そのような時は対象のプロパティにIgnoreDataMember属性を付与することでシリアライズの対象外にすることができます。 試しにAgeプロパティを対象外にしてみます。

[IgnoreDataMember]
public int Age { get; set; }

シリアライズ結果は以下のようになります。Ageが含まれていないことが確認できます。

{"name":"Kato Jun"}

ちなみに、以下のように属性を何も付与しない場合も同様にシリアライズ対象外となります。

[DataContract]
public class Person
{
    [DataMember(Name = "name")]
    public string Name { get; set; }

    public int Age { get; set; } // これでも対象外となる
}

JSONをオブジェクトにデシリアライズ

今度はJSONをオブジェクトにデシリアライズしてみます。 デシリアライズは以下のように行います。

ms.Position = 0;
var deserialized = (Person)serializer.ReadObject(ms);
WriteLine($"Name: {deserialized.Name}"); // Kato Jun
WriteLine($"Age : {deserialized.Age}");  // 31

簡単ですね!

Json.NET

Json.NETとは

Json.NETはMITライセンスで公開されている.NET用のオープンソースJSONライブラリで、以下の特徴を謳っています。

  • High Performance
    • DataContractJsonSerializerより50%高速
  • LINQ to JSON
    • JSONの作成、パース、検索、変更をJObject、JArray、JValueオブジェクトを使って行える
  • Easy To Use
  • Run Anywhere
    • WindowsでもMonoでもXamarinでも使える
  • JSON Path
    • XPathライクな書き方でJSONのクエリが行える
  • XML Support
    • XMLとJSONの相互変換をサポート

導入

nugetでサクッとインストールできます。 プロジェクトの「パッケージ」を右クリックして「パッケージの追加」をクリックします。

パッケージの追加

「Json.NET」で検索すると出て来るのでチェックを入れて、「Add Package」をクリックします。
本記事執筆時点の最新バージョンは9.0.1です。 add-package_Json.NET

「パッケージ」に「Newtonsoft.Json」が追加されればインストール完了です。 Json.NETインストール完了

オブジェクトをJSONにシリアライズ

以下のように1行でシリアライズできます。

// usingが必要
using Newtonsoft.Json;

// Personオブジェクトをシリアライズ
var json = JsonConvert.SerializeObject(p);
WriteLine($"{json}"); // {"Name":"Kato Jun","Age":31}

JsonProperty属性でJSONのキーを指定する

プロパティ名とは別のキーを指定したい場合はJsonProperty属性を使用します。

public class Person
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("age")]
    public int Age { get; set; }
}

JsonIgnore属性でシリアライズ対象外を設定する

対象のプロパティにJsonIgnore属性を付与することでシリアライズの対象外にすることができます。

[JsonIgnore]
public int Age { get; set; } // このプロパティはシリアライズ対象外となる

他にも属性や機能がいっぱい

Json.NETには他にも指定できる属性や機能が豊富にあります。例えば、JSONにシリアライズした時のプロパティの並び順を制御したりもできちゃいます。 詳細はJson.NET Documentation をご覧ください。

JSONをオブジェクトにデシリアライズ

デシリアライズも簡単にできます。ジェネリックに対応しているのでデシリアライズ時に型を指定できます。

var deserialized = JsonConvert.DeserializeObject<Person>(json);
WriteLine($"Name: {deserialized.Name}"); // Kato Jun
WriteLine($"Age : {deserialized.Age}");  // 31

LINQ to JSON

以下のようにParseメソッドでJSON文字列をJson.NETのオブジェクトに変換できます。

var obj = JObject.Parse(@"{
      'people': [
        {
          'name': 'Kato Jun',
          'age': 31
        },
        {
          'name': 'PIKOTARO',
          'age': 53
        },
        {
          'name': 'Kosaka Daimaou',
          'age': 43
        }
      ]
    }"
);

Json.NETのオブジェクトはLINQが使えます。 以下の例ではageが一番大きい(最年長)人をLINQで取得しています。

// LINQで最年長の人を取得
var oldestPersonName = obj["people"].OrderByDescending(p => p["age"])
                                    .FirstOrDefault();
WriteLine(oldestPersonName);
//{
//  "name": "PIKOTARO",
//  "age": 53
//}

JSON Path

JSON Pathを使ってクエリできます。 以下はageが50以下の人のnameを取得する例です。

var names = obj.SelectTokens("$.people[?(@.age <= 50)].name");
foreach (var name in names)
{
    WriteLine(name);
}
//Kato Jun
//Kosaka Daimaou

JSON Pathについての詳細は# JSONPath - XPath for JSON をご覧ください。

XML Support

JSONをXMLに変換

JsonConvert.DeserializeXmlNodeを使えば、JSONをXMLに変換できます。

            var json = @"
{
  '?xml': {
    '@version': '1.0',
    '@encoding': 'UTF-8',
    '@standalone': 'no'
  },
  'people': {
    'person': [
      {
        '@id': '1',
        'name': 'Kato Jun',
        'age': 31
      },
      {
        '@id': '2',
        'name': 'PIKOTARO',
        'age': 53
      },
      {
        '@id': '3',
        'name': 'Kosaka Daimaou',
        'age': 43
      }
    ]
  }
}
";

var xml = JsonConvert.DeserializeXmlNode(json);
WriteLine(xml.OuterXml);
//<?xml version="1.0" encoding="UTF-8" standalone="no"?>
//<people>
//    <person id="1">
//        <name>Kato Jun</name>
//        <age>31</age>
//    </person>
//    <person id="2">
//        <name>PIKOTARO</name>
//        <age>53</age>
//    </person>
//    <person id="3">
//        <name>Kosaka Daimaou</name>
//        <age>43</age>
//    </person>
//</people>

Attributeは@プレフィックスをつける必要があります。

XMLをJSONに変換

JsonConvert.SerializeXmlNodeを使用します。

var xmlJson = JsonConvert.SerializeXmlNode(xml);
WriteLine(xmlJson);
//{
//  "?xml": {
//    "@version": "1.0",
//    "@encoding": "UTF-8",
//    "@standalone": "no"
//  },
//  "people": {
//    "person": [
//      {
//        "@id": "1",
//        "name": "Kato Jun",
//        "age": "31"
//      },
//      {
//        "@id": "2",
//        "name": "PIKOTARO",
//        "age": "53"
//      },
//      {
//        "@id": "3",
//        "name": "Kosaka Daimaou",
//        "age": "43"
//      }
//    ]
//  }
//}

DynamicJson

DynamicJsonとは

DynamicJsonは、C# 4.0で導入されたdynamicを活用することでJSONを「緩く、手軽に」扱えるようにするライブラリです。 ライセンスはMs-PLです。

導入

nugetでインストール可能です。 本記事執筆時点の最新バージョンは1.2.0です。

add-package_DynamicJson

インストールが完了するとDynamicJson.csが追加されます。ライブラリといっても400行くらいのファイル1つだけなのでとても軽量です。

DynamicJson_cs

アセンブリSystem.Xml.LinqMicrosoft.CSharpも必要なので参照を追加しておきましょう。 System_Xml_Linq Microsoft_CSharp

オブジェクトをJSONにシリアライズ

DynamicJson.Serializeでシリアライズできます。

var jsonString = DynamicJson.Serialize(p);
WriteLine(jsonString); // {"Name":"Kato Jun","Age":31}

JSONをオブジェクトにデシリアライズ

デシリアライズはDynamicJson.Parseで行います。

var obj = (Person)DynamicJson.Parse(jsonString);
WriteLine(obj.Name); // Kato Jun
WriteLine(obj.Age);  // 31

匿名型でJSONを作る

匿名型を使ってJSONをサクッと作れます。

var jsonString = DynamicJson.Serialize(new { Name = "PIKOTARO", Age = 53 });
WriteLine(jsonString); // {"Name":"PIKOTARO","Age":53}

ドット(.)でプロパティにアクセス

DynamicJson.Parseの戻り値(DynamicJson)はdynamic型になっており、プロパティにはドット(.)でアクセス可能です。

var obj = DynamicJson.Parse(jsonString);
Console.WriteLine(obj.Name); // PIKOTARO
Console.WriteLine(obj.Age);  // 53

存在しないプロパティにアクセスすると例外になりますが、IsDefinedで存在チェックができます。

obj.IsDefined("Name"); // true
obj.IsDefined("Nama"); // false

DynamicJsonを編集する

DynamicJsonは可変で以下のようにJavaScriptっぽい書き方で編集することができます。 DynamicJsonから文字列へのシリアライズはToString()を呼ぶだけです。

obj.Name = "PPAP"; // 変更
obj.Delete("Age"); // 削除
obj.Id = 1;        // 追加
Console.WriteLine(obj.ToString()); // {"Name":"PPAP","Id":1}

結局どれを使えばいいの?

これは「作るアプリによる」と言ってしまえばそれまでなのですが、筆者は以下のように考えています。

方法 どんな時につかう?
DataContractJsonSerializer 諸事情によりサードパーティライブラリを使えない時
Json.NET 高機能な検索やパフォーマンスを出したい時
DynamicJson Json.NETほどの機能は不要で、型を事前定義せずに緩く扱いたい時

まとめ

今回は、C#でJSONを扱う方法のメジャーどころをまとめてみました。
もちろん今回取り上げた以外にもJSONを扱う方法はあると思いますが、まずは本記事の内容をおさえておくと良いと思われます。

参考