1. はじめに
リマインダー:シリアライズとは、オブジェクトの状態を文字列・ファイル・ストリームの形で保存して、後でそのオブジェクトを復元(デシリアライズ)できるようにする方法です。復元すると、同じデータを持ったオブジェクトが戻ってきます。
典型的な状況:
1) 例えば名前と年齢を持つユーザーというオブジェクトがある。
2) これを保存する必要がある — ネットワークで送る、ファイルに書く、あるいはJSON形式にするなど。
3) その後、文字列/ファイルからデータを取り出してオブジェクトを復元する — また同じオブジェクトが得られます!
C#ではこれがほんの数行でできます。実際に見てみましょう。
アプリの概要
小さなアプリ「連絡先マネージャー」を作るとします。シリアライズしたいクラスとしてPersonがあります。
public class Person
{
// シリアライズにはpublicなプロパティが必要!
public string Name { get; set; }
public int Age { get; set; }
// XmlSerializerのためにパラメータ無しのコンストラクタが必要
public Person() { }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
この構文に慣れていなくても心配いりません — コースの後半でクラスとプロパティを詳しく扱います。今は実験用のデータモデルだと考えてください。注意点:シリアライズにはNameとAgeのようなpublicプロパティが重要で、XmlSerializerにはデフォルトのpublicコンストラクタが必要です。
2. System.Text.Jsonを使ったJSONへのシリアライズ
最もシンプルな例
約束どおり、見せます!JSONへのシリアライズはこんな感じ:
using System;
using System.Text.Json;
Person person = new Person("アリサ", 28);
// シリアライズ:オブジェクトをJSON文字列に変換する
string json = JsonSerializer.Serialize(person);
Console.WriteLine("JSON:");
Console.WriteLine(json);
画面には何が出る?
JSON:
{"Name":"アリサ","Age":28}
とても簡単です:オブジェクト → JSON。これが魔法です!
デシリアライズ — 元に戻す
次は逆の操作です — JSON文字列からオブジェクトを復元します:
string json = "{\"Name\":\"ボブ\",\"Age\":35}";
// デシリアライズ:JSON文字列からPerson型のオブジェクトを復元する
Person restored = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine("復元されたオブジェクト:");
Console.WriteLine($"名前: {restored.Name}, 年齢: {restored.Age}");
結果:
復元されたオブジェクト:
名前: ボブ, 年齢: 35
注意:データ構造が一致しない場合(たとえばそのプロパティがないなど)、対応するフィールドはデフォルト値のままになります(参照型はnull、数値は0など)。
3. XmlSerializerを使ったXMLのシリアライズ/デシリアライズ
XMLへのシリアライズ — 初歩
using System;
using System.IO;
using System.Xml.Serialization;
Person person = new Person("カチャ", 22);
// Person型のためのシリアライザを作成
var serializer = new XmlSerializer(typeof(Person));
// XMLをファイルに書き込む
using (var stream = new FileStream("person.xml", FileMode.Create))
{
serializer.Serialize(stream, person);
// usingブロックの最後でストリームは自動的に閉じられる
}
Console.WriteLine("XMLファイルを作成しました!");
ファイルperson.xmlには次のような内容が出ます:
<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>カチャ</Name>
<Age>22</Age>
</Person>
重要なポイント:
ファイルへのシリアライズにはストリーム(Stream、たとえばFileStream)を使います。文字列にシリアライズしたい(ネットワーク送信用など)場合はStringWriterを使います:
var serializer = new XmlSerializer(typeof(Person));
using (var sw = new StringWriter())
{
serializer.Serialize(sw, person);
string xmlString = sw.ToString();
Console.WriteLine(xmlString);
}
XMLからのデシリアライズ
using (var stream = new FileStream("person.xml", FileMode.Open))
{
// 必ず目的の型にキャストすること!
Person restored = (Person)serializer.Deserialize(stream);
Console.WriteLine($"名前: {restored.Name}, 年齢: {restored.Age}");
}
繰り返しになりますが、XmlSerializerはシリアライズ対象クラスにデフォルトのpublicコンストラクタが必要です。
4. ファイルと文字列の使い分け
実際の用途では、シリアライズは文字列(ネットワーク送信やDB保存)かファイル(長期保存)に向けて行われます。
文字列へのシリアライズ(たとえばAPI経由で送る場合):
- JSON:JsonSerializer.Serialize(obj)を使う。
- XML:StringWriterを使う。
ファイルへのシリアライズ(たとえばエクスポートやバックアップ):
- JSON:文字列を通常のファイル書き込みで保存する。
- XML:XmlSerializerで直接ストリームに書く。
例:ファイルへのシリアライズと復元(JSON)
using System.IO;
using System.Text.Json;
Person person = new Person("トム", 42);
// 文字列にシリアライズ
string json = JsonSerializer.Serialize(person);
// ファイルに書き込む
File.WriteAllText("contact.json", json);
// ファイルから読み込む
string readJson = File.ReadAllText("contact.json");
Person restored = JsonSerializer.Deserialize<Person>(readJson);
Console.WriteLine($"{restored.Name}, 年齢: {restored.Age}");
5. JSON vs XML の比較
プロセスの可視化
混乱しないように、シリアライズとデシリアライズの流れを図で示します:
flowchart LR
A[オブジェクト] -- シリアライズ --> B[文字列/ファイル/ストリーム]
B -- デシリアライズ --> C[オブジェクト]
A -. JSON または XML .-> B
B -. JSON または XML .-> C
シリアライズは「スーツケースに詰める」、デシリアライズは「家で開ける」とイメージすると分かりやすいです。
比較表
| 機能 | JSON (System.Text.Json) | XML (XmlSerializer) |
|---|---|---|
| 文字列の読み書き | ++ | + |
| ファイルの読み書き | ++ | ++ |
| デフォルトコンストラクタが必要か | いいえ | はい |
| 人間に読みやすいか | ++ | + |
| 厳密なスキーマ(バリデーション) | - | ++ |
| カスタマイズ用の属性による柔軟性 | + | ++ |
| パフォーマンス | ++ | + |
| インターネット互換性 | ++ | + |
++ — とても良い、+ — 普通、- — サポートされていない
6. アプリにシリアライズ機能を追加する方法
「連絡先マネージャー」で連絡先リストをファイルに保存して復元する機能を追加するとしましょう。
コンテキスト:連絡先のリスト(List<Person>)があるとします。
List<Person> contacts = new List<Person>
{
new Person("ヴァーシャ", 30),
new Person("ペーチャ", 25),
new Person("マーシャ", 27)
};
// すべての連絡先を保存 — JSONにシリアライズ
string jsonContacts = JsonSerializer.Serialize(contacts);
File.WriteAllText("contacts.json", jsonContacts);
// 連絡先リストを復元
string readContactsJson = File.ReadAllText("contacts.json");
List<Person> restored = JsonSerializer.Deserialize<List<Person>>(readContactsJson);
foreach (var c in restored)
{
Console.WriteLine($"{c.Name}, 年齢: {c.Age}");
}
同じことはXMLでもできますが、いくつか注意点があります。XmlSerializerでコレクションをシリアライズするときは、ルート要素として別のラッパークラス(コンテナ)でリストを包むことがよくあります。そうするとフォーマットや要素名をコントロールしやすくなります。
7. シリアライズ/デシリアライズでよくあるミス
エラー1:シリアライズとデシリアライズで型が一致しない。
List<Person>をシリアライズしたら、デシリアライズするときも同じくList<Person>に戻す必要があります。List<object>やIEnumerable<Person>にするとエラーや予期しない結果になります。
エラー2:非publicなフィールドやプロパティをシリアライズしようとする。
一般的なシリアライザ(JsonSerializer、XmlSerializer)はpublicメンバーを扱います。プロパティにpublicなgetter/setterがないと、値がJSON/XMLに入らず、なぜnullになっているのか悩むことになります。
エラー3:パラメータ無しコンストラクタがない。
XmlSerializerにはデフォルトのpublicコンストラクタが必須です。ないとデシリアライズ時に例外が発生します。
エラー4:オブジェクト参照の扱いを誤解する。
あるオブジェクトが別のオブジェクトへの参照を持っている場合、シリアライズは「値として」入れます。参照そのものは保存されないため、データの重複や循環参照の問題が発生することがあります。
エラー5:シリアライズ形式を混同する。
XMLとJSONは別々のフォーマットで別々のシリアライザが必要です。JSON文字列をXmlSerializerに渡したり、その逆をするとエラーになります。
GO TO FULL VERSION