.NET Framework 2.0 コア機能解説
〜 第 9 回 シリアル化 〜
中 博俊
MSMVP for C#
■シリアル化 とは
皆さんはプログラムを作成するときにクラスなどを作成して、データを保持していたりすると思います。
ただこのメモリ上のデータは実体を保持している物もありますが、参照だけを保持しているなどという場合が多いと思います。
このようなメモリ上のデータはそのままファイルに保存することはできませんし、ネットワークを介して別のコンピュータに送ることもできません。完全に元に戻せるバイトの並び (シリアル) にすることを、シリアル化 (Serialize) / 逆シリアル化 (Deserialize) と言います。
このシリアル化をサポートする技術を .NET Framework では手厚く準備していますが、 .NET Framework2.0 になってより改善された 2 点について書きたいと思います。
■バージョン トレラントなシリアル化
トレラントとは寛容なという意味で、バージョンの変化に寛容なシリアル化という意味の機能です。簡単なクラスのシリアライズのサンプルは以下のようなものになります。
C#
[Serializable]
public class SerializedClass
{
public string TextA;
}
〜〜
private void SaveButton_Click(object sender, EventArgs e)
{
SerializedClass sc = new SerializedClass();
sc.TextA = this.textBox1.Text;
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using( System.IO.FileStream fs = new System.IO.FileStream(@"c:\temp\test.bin", System.IO.FileMode.Create))
{
bf.Serialize(fs, sc);
}
this.textBox1.Text = "";
}
VB
<Serializable()> _
Public Class SerializedClass
Public TextA As String
End Class
〜〜
Private Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveButton.Click
Dim sc As New SerializedClass()
sc.TextA = Me.textBox1.Text
Dim bf = New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Using fs As New System.IO.FileStream("c:\temp\test.bin", System.IO.FileMode.Create)
bf.Serialize(fs, sc)
End Using
Me.textBox1.Text = ""
End Sub
このように Serializable 属性が付いているクラスを BinaryFormatter に渡すという簡易な方法で、シリアル化 / 逆シリアル化を行ってくれます。
SerializableAttribute クラス
http://msdn2.microsoft.com/ja-jp/library/system.serializableattribute(VS.80).aspx
BinaryFormatter クラス
http://msdn2.microsoft.com/ja-jp/library/system.runtime.serialization.formatters.binary.binaryformatter(VS.80).aspx
ただしシリアル化する情報が1つでも増えた場合にはどうなるでしょうか。 SerializedClass に 1 つ項目をそのまま増やしてみて、それを .NET Framework1.1 で実行してみましょう。
このように .NET Framework1.1 までのシリアル化 / 逆シリアル化は厳密に同じオブジェクトである必要がありました。
バージョンによるクラスの整合性に関して本来はプログラマが対応するコードを書かなければいけません。
ですが単純に項目が追加になっただけで、古いバージョンのデータを開いた場合には Null が設定されているだけでよいという場合が大多数でそのような場合には、 OptionalField 属性を利用します。
OptionalFieldAttribute クラス
http://msdn2.microsoft.com/ja-jp/library/system.runtime.serialization.optionalfieldattribute(vs.80).aspx
[Serializable]
public class SerializedClass
{
public string TextA;
[OptionalField]
public string TextB;
}
<Serializable()> _
Public Class SerializedClass
Public TextA As String
<OptionalField()> _
Public TextB As String
End Class
このように指定すると、逆シリアル化の際に OptionalField 属性の付いているフィールドは無視するようになります。
■XML シリアル化
先ほどのシリアル化はバイナリ形式でしたが、 XML 形式で保存すると人間がテキストとして見ることができるようになり非常に便利です。
.NET Frameworkは1.0 から XMLSerializer を搭載していましたが、クラス定義から XML の出力方法を決定するにあたりプログラムの実行中に決定していました。
XmlSerializer クラス http://msdn2.microsoft.com/ja-jp/library/system.xml.serialization.xmlserializer(VS.80).aspx
これはプログラムを作成する際に決定できる事柄ですので、今回新たに Sgen というツールが提供されています。
XML シリアライザ ジェネレータ ツール (Sgen.exe) http://msdn2.microsoft.com/ja-jp/library/bk3w6240(VS.80).aspx
まずスタートメニューの Visual Studio 2005 のコマンドラインから、コマンドプロンプトを立ち上げます。
sgen というコマンドに続いて、 /assembly: で対象になるアセンブリ (EXEかDLL) を指定します。 /out: で出力先のディレクトリを指定します。以下のような感じになります。
C:\Program Files\Microsoft Visual Studio 8\VC>sgen /assembly:"C:\temp\9-Serialization\BinarySerialize-CS\bin\Debug\BinarySerialize-CS.exe" /out:C:\temp\9-Serialization
Microsoft (R) Xml Serialization support utility
[Microsoft (R) .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation. All rights reserved.
シリアル化アセンブリの名前です: BinarySerialize-CS.XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
アセンブリ C:\temp\9-Serialization\BinarySerialize-CS\bin\Debug\BinarySerialize-CS.exe --> 'C:\temp\9-Serialization\BinarySerialize-CS.XmlSerializers.dll' に対してシリアル化アセンブリを生成しました。
この出力された DLL を参照することで、対象のクラス専用のシリアライザが利用できるようになります。
シリアル化するクラス専用の DLL を作成しておき、 DLL から自動的に DLL を作成するようにしておくと便利です。
C#
Microsoft.Xml.Serialization.GeneratedAssembly.SerializedClassSerializer scs = new Microsoft.Xml.Serialization.GeneratedAssembly.SerializedClassSerializer();
SerializedClass sc = new SerializedClass();
sc.TextA = this.textBox1.Text;
sc.TextB = this.textBox2.Text;
using( System.IO.FileStream fs = new System.IO.FileStream(@"c:\temp\test.xml", System.IO.FileMode.Create))
{
scs.Serialize(fs, sc);
}
VB
Dim scs As New Microsoft.Xml.Serialization.GeneratedAssembly.SerializedClassSerializer()
Dim sc As New SerializedClass()
sc.TextA = Me.textBox1.Text
sc.TextB = Me.textBox2.Text
Using fs As New System.IO.FileStream("c:\temp\test.xml", System.IO.FileMode.Create)
scs.Serialize(fs, sc)
End Using
■さいごに
シリアル化はバージョン管理も含めかなり仕様を確定させるのが難しい分野です。 .NET Framework 2.0 になり、いろいろな意味で柔軟になっているので、いろいろと試してみてください。
■参考資料
バージョン トレラントなシリアル化
http://msdn2.microsoft.com/ja-jp/library/ms229752(VS.80).aspx
|