前回は、ファイル変更の監視と、オブジェクトを保存可能な形へ変換する考え方を見ました。
今回は、実際にオブジェクトを XML と JSON に変換し、ファイルへ保存・復元してみます。
現在の .NET では JSON を使う場面が非常に多いですが、XML も既存システム連携や文書構造を持つデータでは今でも使われます。
両方の考え方を知っておくと、保存形式を選ぶときの判断材料が増えます。
サンプル用の型
まず、保存対象の型を用意します。
public class Person
{
public string Name { get; set; } = "";
public int Age { get; set; }
}
public class Department
{
public string Name { get; set; } = "";
public List<Person> Members { get; set; } = new();
}
サンプルデータです。
Department department = new Department
{
Name = "Development",
Members =
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 28 }
}
};
Department が複数の Person を持つため、単一オブジェクトではなく小さなオブジェクトグラフになっています。
XML として保存する
XML への変換には XmlSerializer を使えます。
using System.Xml.Serialization;
var serializer = new XmlSerializer(typeof(Department));
using FileStream stream = File.Create("department.xml");
serializer.Serialize(stream, department);
生成される XML は概念的には次のような形です。
<Department>
<Name>Development</Name>
<Members>
<Person>
<Name>Alice</Name>
<Age>30</Age>
</Person>
<Person>
<Name>Bob</Name>
<Age>28</Age>
</Person>
</Members>
</Department>
XML はタグによって構造が明示されるため、人間にも読みやすい形式です。
XML から復元する
保存した XML からオブジェクトを復元します。
using System.Xml.Serialization;
var serializer = new XmlSerializer(typeof(Department));
using FileStream stream = File.OpenRead("department.xml");
Department? restored = serializer.Deserialize(stream) as Department;
if (restored != null)
{
Console.WriteLine(restored.Name);
foreach (Person member in restored.Members)
{
Console.WriteLine($"{member.Name}: {member.Age}");
}
}
XmlSerializer を使う型は、public な引数なしコンストラクターや public プロパティを前提にすることが多いです。
ドメインモデルをそのまま保存対象にするより、保存用の DTO を分ける設計もよく使われます。
XML の要素名を調整する
属性を使うと、XML 上の名前を調整できます。
using System.Xml.Serialization;
[XmlRoot("department")]
public class DepartmentXml
{
[XmlElement("name")]
public string Name { get; set; } = "";
[XmlArray("members")]
[XmlArrayItem("person")]
public List<PersonXml> Members { get; set; } = new();
}
public class PersonXml
{
[XmlElement("name")]
public string Name { get; set; } = "";
[XmlElement("age")]
public int Age { get; set; }
}
これにより、外部システムが期待する XML 形式へ合わせやすくなります。
XML は柔軟ですが、属性による調整が増えすぎるとモデルが保存形式に引きずられます。
複雑な連携では、専用の XML 用 DTO を作ると保守しやすくなります。
JSON として保存する
JSON への変換には System.Text.Json を使えます。
using System.Text.Json;
var options = new JsonSerializerOptions
{
WriteIndented = true
};
string json = JsonSerializer.Serialize(department, options);
await File.WriteAllTextAsync("department.json", json);
出力は概念的には次のようになります。
{
"Name": "Development",
"Members": [
{
"Name": "Alice",
"Age": 30
},
{
"Name": "Bob",
"Age": 28
}
]
}
WriteIndented = true を指定すると、人間が読みやすいように整形されます。
ログや設定ファイルでは読みやすさが重要になることが多いです。
JSON から復元する
using System.Text.Json;
string json = await File.ReadAllTextAsync("department.json");
Department? restored = JsonSerializer.Deserialize<Department>(json);
if (restored != null)
{
Console.WriteLine(restored.Name);
foreach (Person member in restored.Members)
{
Console.WriteLine($"{member.Name}: {member.Age}");
}
}
System.Text.Json は現在の .NET で標準的に使いやすい JSON API です。
Web API、設定、保存ファイルなど幅広い場面で利用できます。
JSON のプロパティ名を調整する
JSON のプロパティ名を小文字やスネークケースにしたい場合があります。
個別に指定するなら JsonPropertyName を使います。
using System.Text.Json.Serialization;
public class PersonJson
{
[JsonPropertyName("name")]
public string Name { get; set; } = "";
[JsonPropertyName("age")]
public int Age { get; set; }
}
全体的にキャメルケースへ変換するなら、オプションで指定できます。
var options = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
この場合、Name は name、Members は members として出力されます。
保存したくないプロパティ
保存したくない値には、JSON では JsonIgnore を使えます。
using System.Text.Json.Serialization;
public class UserSettings
{
public string Theme { get; set; } = "light";
[JsonIgnore]
public string TemporaryToken { get; set; } = "";
}
XML では XmlIgnore を使えます。
using System.Xml.Serialization;
public class UserSettingsXml
{
public string Theme { get; set; } = "light";
[XmlIgnore]
public string TemporaryToken { get; set; } = "";
}
一時値、キャッシュ、計算で求められる値、秘密情報などは、保存対象から外すことを検討します。
形式を選ぶ考え方
JSON と XML のどちらが良いかは、用途によります。
JSON が向いている場面:
- Web API と連携する
- 設定ファイルとして扱う
- 軽量で読みやすい形式が欲しい
- JavaScript やフロントエンドとやり取りする
XML が向いている場面:
- 既存システムが XML を要求している
- 文書的な構造を扱う
- XML スキーマや名前空間が必要
- 属性と要素を明確に使い分けたい
新しい .NET アプリケーションの保存形式としては、JSON を選ぶことが多いです。
ただし、相手システムや業務上の制約がある場合は、それに合わせるのが現実的です。
バージョン変更に備える
保存形式は、一度外へ出ると長く残ります。
後からプロパティを追加・削除・改名すると、古いファイルとの互換性が問題になります。
たとえば、次のようにプロパティを追加するのは比較的安全です。
public class Person
{
public string Name { get; set; } = "";
public int Age { get; set; }
public string Email { get; set; } = "";
}
一方、既存プロパティの名前を変えると、古いファイルから値が復元できなくなる可能性があります。
長期保存するデータでは、次のような工夫を考えます。
- 保存形式にバージョン番号を持たせる
- DTO を分ける
- 古い形式から新しい形式への移行処理を書く
- プロパティ名を不用意に変えない
まとめ
オブジェクトをファイルへ保存するには、XML や JSON のような形式へ変換します。
XML は構造表現や既存連携に強く、JSON は軽量で現代の .NET アプリケーションと相性が良い形式です。
保存形式化は、単なる読み書きではありません。
どの値を保存するか、どの形式を選ぶか、将来のバージョン変更にどう備えるかまで含めて設計すると、長く扱いやすいデータになります。