C#でオブジェクトをファイルやネットワーク経由で保存・転送したい場面、よくありますよね。そんなときに不可欠なのが [Serializable]
属性です。しかし、単に属性を付ければOKと思っていたら、意外な落とし穴にハマることも。この記事では、[Serializable]
の基本的な使い方から、実務でありがちな注意点、さらには ISerializable
や JSON との関係についてもわかりやすく解説します。データの永続化や通信処理を扱う開発者にとって役立つ知識が得られます。
Serializable属性の基本とその役割
C#でオブジェクトを保存・転送する際に使用されるのが[Serializable]
属性です。これは、対象のクラスを「シリアライズ可能」とマークするための属性であり、バイナリ形式やXML、JSONなどでの保存や転送が可能になります。具体的には、.NETのシリアライザーがオブジェクトの状態を保存・復元できるようにします。
基本的な使い方
C#の例
[Serializable]
public class Person
{
public string Name;
public int Age;
}
このようにクラスに[Serializable]
属性を付けるだけで、BinaryFormatter
などのシリアライザーを使ってオブジェクトをファイルやメモリに保存・復元できるようになります。
- ✅ アクセス修飾子(public/private)に関係なく、すべてのフィールドがシリアライズ対象になります。
- ✅ 継承されたフィールドも対象に含まれます。
ただし、実務で使う際にはいくつかの注意点があります。
代表的な用途と制限
[Serializable]
は多くのシナリオで使われますが、同時に制限も存在します。
主な用途
- ファイルへの保存:アプリ終了後にデータを復元できるように保存。
- ネットワーク通信:Web APIやソケット通信でオブジェクトを送信。
- ASP.NETのセッション保存:ユーザー情報をセッションに格納。
注意点と制限
- ✅ 非シリアライズ可能なフィールドがあると例外発生
たとえば、
Stream
やdelegate
型などはシリアライズできず、含まれていると実行時に例外が発生します。 - ✅ イベントやデリゲートは対象外
状態を持たないこれらの要素は、基本的にシリアライズされません。
- ✅ シリアライズ除外には
[NonSerialized]
を使用
C#の例
[Serializable]
public class Config
{
public string AppName;
[NonSerialized]
public string TempPath; // 一時的な情報なので保存しない
}
これにより、必要なデータだけをシリアライズ対象とする柔軟な設計が可能になります。
BinaryFormatterは非推奨?代替手段を考える
かつては標準的に使用されていたBinaryFormatter
ですが、.NET 5以降、Microsoftはこのクラスの使用を非推奨としています。
非推奨の理由
- 任意のオブジェクト生成が可能であるため、リモートコード実行などのセキュリティリスクがあります。
※ 参考:BinaryFormatterセキュリティガイド – Microsoft Docs
推奨される代替手段
- ✅
System.Text.Json
:高速・軽量。ASP.NET Coreに標準対応。 - ✅
Newtonsoft.Json
(Json.NET):広く使われており機能が豊富。 - ✅
XmlSerializer
:設定ファイルなどに適したXML形式。 - ✅ Protocol Buffers / MessagePack:高速・高効率なバイナリ形式。
これらは、安全性や可読性、保守性の面でBinaryFormatterよりも優れています。
柔軟な制御が必要な場合:ISerializableの実装
クラス構造が将来的に変更される可能性がある場合や、保存対象を細かく制御したい場合は、ISerializable
インターフェースの実装が有効です。
実装例
[Serializable]
public class Person : ISerializable
{
public string Name;
public int Age;
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", Name);
info.AddValue("Age", Age);
}
protected Person(SerializationInfo info, StreamingContext context)
{
Name = info.GetString("Name");
Age = info.GetInt32("Age");
}
}
- ✅
GetObjectData
メソッドで保存対象を明示 - ✅ 特殊コンストラクタで復元時の処理を定義
将来的にプロパティが追加されても、シリアライズ対象を調整することでバージョン互換性を維持できます。
事例:セッションストレージでの活用
ASP.NETでは、セッション情報としてオブジェクトを保存することがあります。その際、対象のクラスに [Serializable]
属性が付いていないと、シリアライズエラーが発生します。
実用例
[Serializable]
public class UserSession
{
public string UserId;
public string Role;
}
// セッションへの保存
UserSession user = new UserSession { UserId = "u001", Role = "Admin" };
Session["LoginUser"] = user;
- ✅
[Serializable]
がないと、セッション保存時に例外が発生 - ✅ 特に Web Farm構成(複数台サーバー)では、セッションの共有が必要なため必須
Web Farm環境では、セッション情報がサーバー間で移動するため、シリアライズが必要となるのです。
まとめ
C#の[Serializable]
属性は、データの永続化や通信において欠かせない技術です。使い方はシンプルですが、以下の点に注意することで、より安全かつ保守性の高い設計が可能になります。
BinaryFormatter
の使用は避け、JSONやXMLなどの安全な代替手段を使う- デリゲートや非シリアライズ対象のフィールドには注意
- 柔軟な保存処理には
ISerializable
を活用 - ASP.NETなどのセッション処理では、
[Serializable]
の指定を忘れずに
適切なシリアライズ設計は、アプリケーションの安定性と信頼性を大きく向上させます。ぜひ、今後の開発に活かしてください。
コメント