次の方法で共有


バージョン トレラントなシリアル化

.NET Framework のバージョン 1.0 および 1.1 では、あるバージョンのアプリケーションから次バージョンに移行しても再利用できる、シリアル化可能な型の作成に問題がありました。フィールドを追加して型を変更すると、次のような問題が発生することがありました。

  • 以前のバージョンのアプリケーションは、元の型の新バージョンを逆シリアル化するように要求されると例外をスローする。

  • 新しいバージョンのアプリケーションは、データの不足している以前のバージョンの型を逆シリアル化すると例外をスローする。

バージョン トレラントなシリアル化 (VTS : Version Tolerant Serialization) は、シリアル化可能な型を後からでも簡単に変更できるように .NET Framework 2.0 に導入された機能セットです。具体的には、VTS 機能は、SerializableAttribute 属性が適用されているクラスに対して使用可能です。VTS を使用すると、これらのクラスに対して、型の他のバージョンとの互換性を失うことなく、新しいフィールドを追加できます。実際に動作するサンプル アプリケーションについては、「シリアル化の複数バージョンに対応する技術サンプル」を参照してください。

VTS 機能は、BinaryFormatter を使用する場合に使用可能です。また、SoapFormatter を使用する場合は、外部データ トレランスを除くすべての機能も使用可能になります。シリアル化でこれらのクラスを使用する方法の詳細については、「バイナリ シリアル化」を参照してください。

Noteメモ :

BinaryFormatter に対する外部データ トレランス機能は、今後、.NET Framework 1.1 の更新プログラムとして提供される可能性があります。

機能の一覧

この機能セットの内容は次のとおりです。

  • 外部データまたは予期しないデータに対するトレランス。これにより、新しいバージョンの型は以前のバージョンにデータを送信できます。

  • 不足している省略可能なデータに対するトレランス。これにより、以前のバージョンは新しいバージョンにデータを送信できます。

  • シリアル化のコールバック。これにより、データが不足している場合でも、既定値をインテリジェントに設定できます。

この他にも、省略可能なフィールドが新たに追加されたときに宣言する機能があります。これは、OptionalFieldAttribute 属性の VersionAdded プロパティです。

次に、これらの各機能について詳しく説明します。

外部データまたは予期しないデータに対するトレランス

これまでは、逆シリアル化の実行中に外部データまたは予期しないデータが検出されると、必ず例外がスローされていました。VTS では、同じ状況で、例外がスローされるのではなく、外部データまたは予期しないデータはすべて無視されます。これにより、新しいバージョンの型 (新たにフィールドが追加されているバージョン) を使用するアプリケーションが、同じ型の以前のバージョンを必要とするアプリケーションに情報を送ることが可能になります。

次の例では、以前のアプリケーションが新しいバージョンを逆シリアル化する際、バージョン 2.0 の Address クラスの CountryField に含まれる追加データは無視されます。

// Version 1 of the Address class.
[Serializable]
public class Address
{
    public string Street;
    public string City;
}
// Version 2.0 of the Address class.
[Serializable]
public class Address
{
    public string Street;
    public string City;
    // The older application ignores this data.
    public string CountryField;
}
' Version 1 of the Address class.
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
End Class

' Version 2.0 of the Address class.
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
    ' The older application ignores this data.
    Public CountryField As String
End Class

不足しているデータに対するトレランス

OptionalFieldAttribute 属性をフィールドに適用することで、このフィールドを省略可能としてマークできます。逆シリアル化の実行中に省略可能なデータが不足していることが検出されても、シリアル化エンジンはデータの不足を無視し、例外をスローしません。そのため、以前のバージョンの型を必要とするアプリケーションでも、同じ型の新しいバージョンを必要とするアプリケーションにデータを送信できます。

バージョン 2.0 の Address クラスで、CountryField フィールドが省略可能としてマークされるコード例を次に示します。バージョン 2.0 を必要とする新しいアプリケーションに対して、以前のアプリケーションがバージョン 1 を送信しても、データの不足は無視されます。

[Serializable]
public class Address
{
    public string Street;
    public string City;

    [OptionalField]
    public string CountryField;
}
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String

    <OptionalField> _
    Public CountryField As String
End Class

シリアル化のコールバック

シリアル化のコールバックは、シリアル化および逆シリアル化プロセスに 4 つのポイントでフックを提供する機構です。

属性 関連付けられているメソッドが呼び出されるタイミング 一般的な使用法

OnDeserializingAttribute

逆シリアル化前 *

省略可能なフィールドの既定値を初期化します。

OnDeserializedAttribute

逆シリアル化後

他のフィールドの内容に基づいて、省略可能なフィールドの値を固定します。

OnSerializingAttribute

シリアル化前

シリアル化の準備を行います。たとえば、省略可能なデータ構造の作成などです。

OnSerializedAttribute

シリアル化後

シリアル化イベントをログに記録します。

* このコールバックは、逆シリアル化コンストラクタ (存在する場合) の前に呼び出されます。

コールバックの使用

コールバックを使用するには、StreamingContext パラメータを受け取るメソッドに適切な属性を適用します。これらの属性では、1 つのクラスにつき 1 つのメソッドだけをマークできます。次に例を示します。

[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
    CountryField = "Japan";
}
[OnDeserializing]
private void SetCountryRegionDefault(StreamingContext sc)
{
    CountryField = "Japan";
}

これらのメソッドの使用目的は、バージョン管理です。省略可能なフィールドのデータが不足していると、逆シリアル化の実行中、このフィールドが正しく初期化されないことがあります。この問題は、正しい値を割り当てるメソッドを作成してから、このメソッドに OnDeserializingAttribute または OnDeserializedAttribute 属性を適用することで解決できます。

型のコンテキストから見たメソッドのコード例を次に示します。以前のバージョンのアプリケーションが新しいバージョンのアプリケーションに Address クラスのインスタンスを送信すると、CountryField フィールドのデータが不足することになります。しかし、逆シリアル化後、このフィールドは既定値である "Japan" に設定されます。

[Serializable]
public class Address
{
    public string Street;
    public string City;
    [OptionalField]
    public string CountryField;

    [OnDeserializing]
    private void SetCountryRegionDefault (StreamingContext sc)
    {
        CountryField = "Japan";
    }
}
<Serializable> _
Public Class Address
    Public Street As String
    Public City As String
    <OptionalField> _
    Public CountryField As String

    <OnDeserializing> _
    Private Sub SetCountryRegionDefault(StreamingContext sc)
        CountryField = "Japan";
    End Sub
End Class

VersionAdded プロパティ

OptionalFieldAttribute には VersionAdded プロパティがあります。.NET Framework バージョン 2.0 では、これは使用されません。ただし、将来のシリアル化エンジンとの型の互換性を維持するため、このプロパティを正しく設定しておくことが重要です。

このプロパティは、指定のフィールドが追加された型のバージョンを示します。次の例で示すように、このプロパティ値は型が変更されるつど、厳密に 1 ずつ増やす必要があります (開始値は 2)。

// Version 1.0
[Serializable]
public class Person
{
    public string FullName;
}

// Version 2.0
[Serializable]
public class Person
{
    public string FullName;

    [OptionalField(VersionAdded = 2)]
    public string NickName;
    [OptionalField(VersionAdded = 2)]
    public DateTime BirthDate;
}

// Version 3.0
[Serializable]
public class Person
{
    public string FullName;

    [OptionalField(VersionAdded=2)]
    public string NickName;
    [OptionalField(VersionAdded=2)]
    public DateTime BirthDate;

    [OptionalField(VersionAdded=3)]
    public int Weight;
}
' Version 1.0
<Serializable> _
Public Class Person
    Public FullName
End Class

' Version 2.0
<Serializable> _
Public Class Person
    Public FullName As String

    <OptionalField(VersionAdded := 2)> _
    Public NickName As String
    <OptionalField(VersionAdded := 2)> _
    Public BirthDate As DateTime
End Class

' Version 3.0
<Serializable> _
Public Class Person
    Public FullName As String

    <OptionalField(VersionAdded := 2)> _
    Public NickName As String
    <OptionalField(VersionAdded := 2)> _
    Public BirthDate As DateTime

    <OptionalField(VersionAdded := 3)> _
    Public Weight As Integer
End Class

ベスト プラクティス

バージョン管理が正しく行われるように、バージョン間で型を変更するときには次の規則に従ってください。

  • シリアル化したフィールドは削除しない。

  • NonSerializedAttribute 属性が以前のバージョンでフィールドに適用されていなかった場合は、新しいバージョンの該当フィールドにも適用しない。

  • シリアル化したフィールドの名前または型は変更しない。

  • 新しいシリアル化フィールドを追加する場合は、OptionalFieldAttribute 属性を適用する。

  • 以前のバージョンでシリアル化可能ではなかったフィールドから NonSerializedAttribute 属性を削除する場合は、OptionalFieldAttribute 属性を適用する。

  • すべての省略可能なフィールドに対して、既定値として 0 または null が許容される場合以外は、シリアル化コールバックを使用して意味のある既定値を設定する。

将来のシリアル化エンジンとの型の互換性を維持するには、次のガイドラインに従ってください。

  • 常に OptionalFieldAttribute 属性の VersionAdded プロパティを正しく設定する。

  • バージョンの分岐は避ける。

参照

関連項目

SerializableAttribute
BinaryFormatter
SoapFormatter
VersionAdded
OptionalFieldAttribute
OnDeserializingAttribute
OnDeserializedAttribute
OnDeserializingAttribute
OnSerializedAttribute
StreamingContext
NonSerializedAttribute

その他の技術情報

バイナリ シリアル化