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

.NET Framework のバージョン 1.0 および 1.1 では、アプリケーションのあるバージョンから次のバージョンに移行しても再利用できる、シリアル化可能な型の作成に問題がありました。In version 1.0 and 1.1 of the .NET Framework, creating serializable types that would be reusable from one version of an application to the next was problematic. フィールドを追加して型を変更すると、次のような問題が発生していました。If a type was modified by adding extra fields, the following problems would occur:

  • 以前のバージョンのアプリケーションは、古い型の新しいバージョンを逆シリアル化するように要求すると例外をスローする。Older versions of an application would throw exceptions when asked to deserialize new versions of the old type.

  • 新しいバージョンのアプリケーションは、データが欠落している以前のバージョンの型を逆シリアル化すると例外をスローする。Newer versions of an application would throw exceptions when deserializing older versions of a type with missing data.

バージョン トレラントなシリアル化 (VTS: Version Tolerant Serialization) は、.NET Framework 2.0 で導入された機能セットで、シリアル化可能な型を、長期にわたって簡単に変更できるようにします。Version Tolerant Serialization (VTS) is a set of features introduced in .NET Framework 2.0 that makes it easier, over time, to modify serializable types. 具体的には、VTS 機能が、ジェネリック型を含め、SerializableAttribute 属性が適用されているクラスに対して有効です。Specifically, the VTS features are enabled for classes to which the SerializableAttribute attribute has been applied, including generic types. VTS を使用すると、他のバージョンの型との互換性を失うことなく、これらのクラスに新しいフィールドを追加できます。VTS makes it possible to add new fields to those classes without breaking compatibility with other versions of the type. 動作するサンプル アプリケーションについては、「バージョン トレラントなシリアル化の技術サンプル」(バージョン トレラントなシリアル化テクノロジのサンプル) を参照してください。For a working sample application, see Version Tolerant Serialization Technology Sample.

VTS 機能は、BinaryFormatter を使用する場合に有効になります。The VTS features are enabled when using the BinaryFormatter. また、SoapFormatter を使用する場合は、外部データの複数バージョン対応機能を除くすべての機能が有効になります。Additionally, all features except extraneous data tolerance are also enabled when using the SoapFormatter. シリアル化でこれらのクラスを使用する方法の詳細については、「バイナリ シリアル化」を参照してください。For more information about using these classes for serialization, see Binary Serialization.

警告

バイナリ シリアル化は危険です。Binary serialization can be dangerous. 信頼できないソースからのデータの逆シリアル化、および管理下にないシステムへのラウンドトリップのシリアル化をしてはいけません。Never deserialize data from an untrusted source and never round-trip serialized data to systems not under your control.

機能の一覧Feature list

この機能セットの内容は次のとおりです。The set of features includes the following:

  • 外部データまたは予期しないデータの複数バージョン対応。Tolerance of extraneous or unexpected data. これにより、型の新しいバージョンから以前のバージョンにデータを送信できます。This enables newer versions of the type to send data to older versions.

  • 欠落しているオプション データの複数バージョン対応。Tolerance of missing optional data. これにより、以前のバージョンから新しいバージョンにデータを送信できます。This enables older versions to send data to newer versions.

  • シリアル化のコールバック。Serialization callbacks. これにより、データが欠落している場合に、既定値の高度な設定ができます。This enables intelligent default value setting in cases where data is missing.

さらに、オプション フィールドが新たに追加されたときに宣言を生成する機能があります。In addition, there is a feature for declaring when a new optional field has been added. これは、VersionAdded 属性の OptionalFieldAttribute プロパティです。This is the VersionAdded property of the OptionalFieldAttribute attribute.

これらの機能の詳細については、以下で説明します。These features are discussed in greater detail below.

外部データまたは予期しないデータの複数バージョン対応Tolerance of extraneous or unexpected data

これまで、逆シリアル化中に外部データまたは予期しないデータが検出されると、例外がスローされていました。In the past, during deserialization, any extraneous or unexpected data caused exceptions to be thrown. VTS ではこのような場合、例外がスローされるのではなく、外部データまたは予期しないデータがすべて無視されます。With VTS, in the same situation, any extraneous or unexpected data is ignored instead of causing exceptions to be thrown. これにより、新しいバージョンの型 (フィールドが追加されたバージョン) を使用するアプリケーションが、同じ型の以前のバージョンを必要とするアプリケーションに情報を送ることができます。This enables applications that use newer versions of a type (that is, a version that includes more fields) to send information to applications that expect older versions of the same type.

次の例では、バージョン 2.0 の CountryField クラスの Address に含まれる追加データは、以前のアプリケーションで新しいバージョンを逆シリアル化する場合、無視されます。In the following example, the extra data contained in the CountryField of version 2.0 of the Address class is ignored when an older application deserializes the newer version.

// 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  

欠落しているデータの複数バージョン対応Tolerance of missing data

OptionalFieldAttribute 属性をフィールドに適用すると、そのフィールドをオプションとしてマークできます。Fields can be marked as optional by applying the OptionalFieldAttribute attribute to them. 逆シリアル化中に、オプション データの欠落が検出されても、シリアル化エンジンはデータが存在しないことを無視し、例外をスローしません。During deserialization, if the optional data is missing, the serialization engine ignores the absence and does not throw an exception. そのため、以前のバージョンの型を必要とするアプリケーションから、同じ型の新しいバージョンを必要とするアプリケーションにデータを送信できます。Thus, applications that expect older versions of a type can send data to applications that expect newer versions of the same type.

バージョン 2.0 の Address クラスで、CountryField フィールドをオプションとしてマークする方法を次の例に示します。The following example shows version 2.0 of the Address class with the CountryField field marked as optional. バージョン 2.0 を必要とする新しいアプリケーションに対して、以前のアプリケーションがバージョン 1 を送信した場合、データが存在しないことは無視されます。If an older application sends version 1 to a newer application that expects version 2.0, the absence of the data is ignored.

[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  

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

シリアル化のコールバックは、次の 4 つの時点でシリアル化プロセスおよび逆シリアル化プロセスにフックする機構です。Serialization callbacks are a mechanism that provides hooks into the serialization/deserialization process at four points.

属性Attribute 関連するメソッドが呼び出されるタイミングWhen the Associated Method is Called 一般的な用途Typical Use
OnDeserializingAttribute 逆シリアル化の前 *Before deserialization.* オプション フィールドの既定値を初期化します。Initialize default values for optional fields.
OnDeserializedAttribute 逆シリアル化の後After deserialization. 他のフィールドの内容に基づいて、オプション フィールドの値を修正します。Fix optional field values based on contents of other fields.
OnSerializingAttribute シリアル化の前Before serialization. シリアル化の準備をします。Prepare for serialization. たとえば、オプションのデータ構造を作成します。For example, create optional data structures.
OnSerializedAttribute シリアル化の後After serialization. シリアル化イベントのログを記録します。Log serialization events.

* このコールバックは、逆シリアル化コンストラクターの前に呼び出されます (存在する場合)。* This callback is invoked before the deserialization constructor, if one is present.

コールバックの使用Using callbacks

コールバックを使用するには、StreamingContext パラメーターを受け取るメソッドに、適切な属性を適用します。To use callbacks, apply the appropriate attribute to a method that accepts a StreamingContext parameter. 各属性でマークできるのは、クラスごとに 1 つのメソッドだけです。Only one method per class can be marked with each of these attributes. 次に例を示します。For example:

[OnDeserializing]  
private void SetCountryRegionDefault(StreamingContext sc)  
{  
    CountryField = "Japan";  
}  
<OnDeserializing>  
Private Sub SetCountryRegionDefault(StreamingContext sc)  
    CountryField = "Japan";  
End Sub  

これらのメソッドの使用目的は、バージョン管理です。The intended use of these methods is for versioning. オプション フィールドにデータがない場合、逆シリアル化の実行中に、このフィールドが正しく初期化されないことがあります。During deserialization, an optional field may not be correctly initialized if the data for the field is missing. この問題を解決するには、正しい値を割り当てるメソッドを作成してから、このメソッドに OnDeserializingAttribute 属性または OnDeserializedAttribute 属性のいずれかを適用します。This can be corrected by creating the method that assigns the correct value, then applying either the OnDeserializingAttribute or OnDeserializedAttribute attribute to the method.

型のコンテキストで使用されるメソッドを次に示します。The following example shows the method in the context of a type. 以前のバージョンのアプリケーションが新しいバージョンのアプリケーションに Address クラスのインスタンスを送信すると、CountryField フィールドのデータが欠落します。If an earlier version of an application sends an instance of the Address class to a later version of the application, the CountryField field data will be missing. しかし、逆シリアル化を行うと、このフィールドは既定値である "Japan" に設定されます。But after deserialization, the field will be set to a default value "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 プロパティThe VersionAdded property

OptionalFieldAttribute には VersionAdded プロパティがあります。The OptionalFieldAttribute has the VersionAdded property. .NET Framework バージョン 2.0 では、このプロパティは使用されません。In version 2.0 of the .NET Framework, this isn't used. ただし、このプロパティを正しく設定して、型が今後のシリアル化エンジンと互換性を保つようにすることが重要です。However, it's important to set this property correctly to ensure that the type will be compatible with future serialization engines.

このプロパティは、指定されたフィールドに追加された型のバージョンを示します。The property indicates which version of a type a given field has been added. 次の例に示すように、このプロパティの値は 2 を開始値として、型が変更されるたびに常に 1 ずつインクリメントする必要があります。It should be incremented by exactly one (starting at 2) every time the type is modified, as shown in the following example:

// 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  

SerializationBinderSerializationBinder

サーバー上とクライアント上では異なるバージョンのクラスが必要なため、ユーザーによっては、シリアル化するクラスと逆シリアル化するクラスを制御することが必要になる場合があります。Some users may need to control which class to serialize and deserialize because a different version of the class is required on the server and client. SerializationBinder は、シリアル化中および逆シリアル化中に使用される実際の型を制御するために使用される抽象クラスです。SerializationBinder is an abstract class used to control the actual types used during serialization and deserialization. このクラスを使用するには、クラスを SerializationBinder から派生させ、BindToName メソッドと BindToType メソッドをオーバーライドします。To use this class, derive a class from SerializationBinder and override the BindToName and BindToType methods. 詳細については、次を参照してください。を制御するシリアル化と逆シリアル化 SerializationBinder を使用したします。For more information, see Controlling Serialization and Deserialization with SerializationBinder.

ベスト プラクティスBest practices

バージョン管理が正しく行われるように、バージョン間で型を変更するときは次の規則に従ってください。To ensure proper versioning behavior, follow these rules when modifying a type from version to version:

  • シリアル化したフィールドを削除しない。Never remove a serialized field.

  • 以前のバージョンでフィールドに NonSerializedAttribute 属性が適用されていない場合、新しいバージョンでもこの属性を適用しない。Never apply the NonSerializedAttribute attribute to a field if the attribute was not applied to the field in the previous version.

  • シリアル化したフィールドの名前または型を変更しない。Never change the name or the type of a serialized field.

  • 新しいシリアル化フィールドを追加する場合は、OptionalFieldAttribute 属性を適用する。When adding a new serialized field, apply the OptionalFieldAttribute attribute.

  • 以前のバージョンでシリアル化できなかったフィールドから NonSerializedAttribute 属性を削除する場合は、OptionalFieldAttribute 属性を適用する。When removing a NonSerializedAttribute attribute from a field (that was not serializable in a previous version), apply the OptionalFieldAttribute attribute.

  • すべてのオプション フィールドに対して、既定値として 0 または null が許容される場合以外は、シリアル化コールバックを使用して意味のある既定値を設定する。For all optional fields, set meaningful defaults using the serialization callbacks unless 0 or null as defaults are acceptable.

型が今後のシリアル化エンジンと互換性を保つようにするには、次のガイドラインに従ってください。To ensure that a type will be compatible with future serialization engines, follow these guidelines:

  • OptionalFieldAttribute 属性には常に VersionAdded を設定する。Always set the VersionAdded property on the OptionalFieldAttribute attribute correctly.

  • バージョンの分岐は避ける。Avoid branched versioning.

関連項目See also