この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
こんにちは!モバイルアプリサービス部の加藤です。
今回は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.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です。
「パッケージ」に「Newtonsoft.Json」が追加されればインストール完了です。
オブジェクトを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です。
インストールが完了するとDynamicJson.csが追加されます。ライブラリといっても400行くらいのファイル1つだけなのでとても軽量です。
アセンブリ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を扱う方法はあると思いますが、まずは本記事の内容をおさえておくと良いと思われます。