シリアル化のガイドライン

このドキュメントには、シリアル化できるように API をデザインする際に考慮すべきガイドラインを示します。

.NET Framework には、さまざまなシリアル化シナリオに合わせて最適化できる 3 つの主なシリアル化テクノロジがあります。 これらのテクノロジ、およびテクノロジに関連した主な Framework 型を次の表に示します。

テクノロジ

関連するクラス

メモ

データ コントラクトのシリアル化

DataContractAttribute

DataMemberAttribute

DataContractSerializer

NetDataContractSerializer

DataContractJsonSerializer

ISerializable

永続化全般

Web サービス

JSON

XML シリアル化

XmlSerializer

XML 形式 フル コントロール

ランタイム シリアル化 (バイナリおよび SOAP)

SerializableAttribute

ISerializable

BinaryFormatter

SoapFormatter

.NET リモート処理

新しい型をデザインする際は、新しい型でどのテクノロジをサポートするかを決める必要があります。 次のガイドラインでその選択方法とサポートの提供方法について説明します。 このガイドラインは、アプリケーションまたはライブラリの実装時に使用するシリアル化テクノロジを決定するためのものではありません。 そのようなガイドラインは API のデザインには直接関係ないため、このトピックのスコープの範囲外となります。

ガイドライン

  • 新しい型をデザインする際にはシリアル化について考えてください。

    シリアル化は、プログラムで型のインスタンスを永続化または変換しなければならないことがあるため、どのような型においてもデザイン上の重要な考慮事項です。

6exf3h2k.collapse_all(ja-jp,VS.120).gifサポートする適切なシリアル化テクノロジの選択

任意の型で 0、または 1 つ以上のシリアル化テクノロジをサポートできます。

  • 使用する型のインスタンスを Web サービスで永続化させる、または使用する必要がある場合は、データ コントラクトのシリアル化をサポートすることを検討してください。

  • 型をシリアル化したときに作成される XML 形式の制御を強化する必要がある場合は、データ コントラクトのシリアル化の代わり、またはこれに加えて XML シリアル化をサポートすることを検討してください。

    これは、データ コントラクトのシリアル化でサポートされていない XML 構築を使用して XML 属性を作成するような一部の相互運用シナリオで必要になることがあります。

  • 使用する型のインスタンスが .NET リモート処理境界を超えて移動する必要がある場合は、ランタイムのシリアル化をサポートすることを検討してください。

  • 一般的な永続化のためにランタイムのシリアル化や XML のシリアル化をサポートしないでください。 データ コントラクトのシリアル化を優先的に使用してください。

6exf3h2k.collapse_all(ja-jp,VS.120).gifデータ コントラクトのシリアル化のサポート

DataContractAttribute を型に適用し、DataMemberAttribute をその型のメンバー (フィールドおよびプロパティ) に適用することによって、型でデータ コントラクトのシリアル化をサポートすることができます。

<DataContract()> Public Class Person
    <DataMember()> Public Property LastName As String
    <DataMember()> Public Property FirstName As String

    Public Sub New(ByVal firstNameValue As String, ByVal lastNameValue As String)
        FirstName = firstNameValue
        LastName = lastNameValue
    End Sub

End Class
    [DataContract]
    class Person
    {

        [DataMember]
        string LastName { get; set; }
        [DataMember]
        string FirstName { get; set; }

        public Person(string firstNameValue, string lastNameValue)
        {
            FirstName = firstNameValue;
            LastName = lastNameValue;
        }
    }

  1. 型を部分信頼で使用する場合は、型のデータ メンバーをパブリックにすることを検討してください。 完全な信頼では、データ コントラクト シリアライザーでパブリックではない型とメンバーのシリアル化と逆シリアル化を行うことが可能ですが、部分信頼の場合、パブリック メンバーのみをシリアル化および逆シリアル化できます。

  2. Data-MemberAttribute を持つすべてのプロパティに getter と setter を実装してください。 データ コントラクト シリアライザーでは、この型の getter と setter の両方がシリアル化可能と見なされる必要があります。 型を部分信頼で使用しない場合は、1 つまたは両方のプロパティ アクセサーを非パブリックにできます。

    <DataContract()> Class Person2
        Private lastNameValue As String
        Private firstNameValue As String
    
        Public Sub New(ByVal firstName As String, ByVal lastName As String)
            Me.lastNameValue = lastName
            Me.firstNameValue = firstName
        End Sub
    
        <DataMember()> Property LastName As String
            Get
                Return lastNameValue
            End Get
    
            Set(ByVal value As String)
                lastNameValue = value
            End Set
    
        End Property
    
        <DataMember()> Property FirstName As String
            Get
                Return firstNameValue
    
            End Get
            Set(ByVal value As String)
                firstNameValue = value
            End Set
        End Property
    
    End Class
    
    [DataContract]
    class Person2
    {
    
        string lastName;
        string firstName;
    
        public Person2(string firstName, string lastName)
        {
            this.lastName = lastName;
            this.firstName = firstName;
        }
    
        [DataMember]
        public string LastName
        { 
            // Implement get and set.
            get { return lastName; }
            private set { lastName = value; }
    
        }
    
        [DataMember]
        public string FirstName
        {
            // Implement get and set.
            get { return firstName; }
            private set { firstName = value; }
        }
    }
    
  3. 逆シリアル化されたインスタンスの初期化には、シリアル化コールバックを使用することを検討してください。

    オブジェクトの逆シリアル化時にはコンストラクターは呼び出されません。 このため、通常の構築時に実行されるすべてのロジックは、シリアル化のコールバックの 1 つとして実装する必要があります。

    <DataContract()> _
    Class Person3
        <DataMember()> Private lastNameValue As String
        <DataMember()> Private firstNameValue As String
        Dim fullNameValue As String
    
        Public Sub New(ByVal firstName As String, ByVal lastName As String)
            lastNameValue = lastName
            firstNameValue = firstName
            fullNameValue = firstName & " " & lastName
        End Sub
    
        Public ReadOnly Property FullName As String
            Get
                Return fullNameValue
            End Get
        End Property
    
        <OnDeserialized()> Sub OnDeserialized(ByVal context As StreamingContext)
            fullNameValue = firstNameValue & " " & lastNameValue
        End Sub
    End Class
    
    [DataContract]
    class Person3
    {
        [DataMember]
        string lastName;
        [DataMember]
        string firstName;
        string fullName;
    
        public Person3(string firstName, string lastName)
        {
            // This constructor is not called during deserialization.
            this.lastName = lastName;
            this.firstName = firstName;
            fullName = firstName + " " + lastName;
        }
    
        public string FullName
        {
            get { return fullName; }
        }
    
        // This method is called after the object 
        // is completely deserialized. Use it instead of the
        // constructror.
        [OnDeserialized] 
        void OnDeserialized(StreamingContext context)
        {
            fullName = firstName + " " + lastName;
        }
    }
    

    OnDeserializedAttribute 属性は最もよく使用されるコールバック属性です。 その他の属性には、OnDeserializingAttribute、OnSeralizingAttribute、および OnSerializedAttribute があります。 これらを使用して、逆シリアル化前、シリアル化前、およびシリアル化後に実行されるコールバックをマークすることができます。

  4. 複雑なオブジェクト グラフを逆シリアル化する場合は、使用する具象型を示す KnownTypeAttribute を使用することを検討してください。

    たとえば、逆シリアル化されたデータ メンバーの型を抽象クラスで表す場合、シリアライザーはインスタンス化してメンバーに割り当てる具象型を判断するために、既知の型の情報が必要になります。 属性を使用して既知の型を指定しない場合、明示的にシリアライザーに渡す (既知の型をシリアライザーのコンストラクターに渡します) か、構成ファイルで指定する必要があります。

    <KnownType(GetType(USAddress)), _
    DataContract()> Class Person4
        <DataMember()> Property fullNameValue As String
        <DataMember()> Property addressValue As USAddress ' Address is abstract
    
        Public Sub New(ByVal fullName As String, ByVal address As Address)
            fullNameValue = fullName
            addressValue = address
        End Sub
    
        Public ReadOnly Property FullName() As String
            Get
                Return fullNameValue
            End Get
    
        End Property
    End Class
    
    <DataContract()> Public MustInherit Class Address
        Public MustOverride Function FullAddress() As String
    End Class
    
    <DataContract()> Public Class USAddress
        Inherits Address
        <DataMember()> Public Property Street As String
        <DataMember()> Public City As String
        <DataMember()> Public State As String
        <DataMember()> Public ZipCode As String
    
        Public Overrides Function FullAddress() As String
            Return Street & "\n" & City & ", " & State & " " & ZipCode
        End Function
    End Class
    
    // The KnownTypeAttribute specifies types to be
    // used during serialization.
    [KnownType(typeof(USAddress))]
    [DataContract]
    class Person4
    {
    
        [DataMember]
        string fullNameValue;
        [DataMember]
        Address address; // Address is abstract
    
        public Person4(string fullName, Address address)
        {
            this.fullNameValue = fullName;
            this.address = address;
        }
    
        public string FullName
        {
            get { return fullNameValue; }
        }
    }
    
    [DataContract]
    public abstract class Address
    {
        public abstract string FullAddress { get; }
    }
    
    [DataContract]
    public class USAddress : Address
    {
    
        [DataMember]
        public string Street { get; set; }
        [DataMember]
        public string City { get; set; }
        [DataMember]
        public string State { get; set; }
        [DataMember]
        public string ZipCode { get; set; }
    
        public override string FullAddress
        {
            get
            {
                return Street + "\n" + City + ", " + State + " " + ZipCode;
            }
        }
    }
    

    既知の型のリストが静的にわからない場合 (Person クラスをコンパイルした場合)、KnownTypeAttribute で実行時に既知の型の一覧を返すメソッドを指すこともできます。

  5. シリアル化可能な型を作成または変更する場合は、上位互換性と下位互換性を考慮してください。

    シリアル化した型の将来のバージョンは、現在のバージョンの型に逆シリアル化でき、その逆も可能であることを念頭に置いてください。 明示的なパラメーターを使用してデータ コントラクト属性にコントラクトを保存する特別な措置を取らない限り、データ メンバーはプライベートで内部データであっても、型の将来のバージョンで名前、型、順序を変更することはできないことを理解しておいてください。シリアル化可能な型に変更を加えるときは、シリアル化の互換性をテストしてください。 新しいバージョンを古いバージョンに逆シリアル化したり、その逆も試してみてください。

  6. 異なるバージョンの型の間でラウンドトリッピングができるように、IExtensibleDataObject インターフェイスを実装することを検討してください。

    インターフェイスを使用すると、ラウンドトリッピングの間にデータが失われないようにシリアライザーで確認することができます。 ExtensionData プロパティにより、現在のバージョンでは未知の、将来使用される型の任意のデータが格納されます。 現在のバージョンを将来のバージョンにシリアル化または逆シリアル化するときに、ExtensionData プロパティ値を通じて、シリアル化されたストリーム内で追加データを使用できます。

    <DataContract()> Class Person5
        Implements IExtensibleDataObject
        <DataMember()> Dim fullNameValue As String
    
        Public Sub New(ByVal fullName As String)
            fullName = fullName
        End Sub
    
        Public ReadOnly Property FullName
            Get
                Return fullNameValue
            End Get
        End Property
        Private serializationData As ExtensionDataObject
        Public Property ExtensionData As ExtensionDataObject Implements IExtensibleDataObject.ExtensionData
            Get
                Return serializationData
            End Get
            Set(ByVal value As ExtensionDataObject)
                serializationData = value
            End Set
        End Property
    End Class
    
    // Implement the IExtensibleDataObject interface.
    [DataContract]
    class Person5 : IExtensibleDataObject
    {
        ExtensionDataObject serializationData;
        [DataMember]
        string fullNameValue;
    
        public Person5(string fullName)
        {
            this.fullNameValue = fullName;
        }
    
        public string FullName
        {
            get { return fullNameValue; }
        }
    
        ExtensionDataObject IExtensibleDataObject.ExtensionData
        {
            get 
            {                 
                return serializationData; 
            }
            set { serializationData = value; }
        }
    }
    

    詳細については、「上位互換性のあるデータ コントラクト」を参照してください。

6exf3h2k.collapse_all(ja-jp,VS.120).gifXML シリアル化のサポート

データ コントラクトのシリアル化は .NET Framework の主な (既定の) シリアル化テクノロジですが、データ コントラクトのシリアル化ではサポートされないシリアル化シナリオがあります。 たとえば、シリアライザーによって作成または使用された XML の形状は完全に制御できません。 そのような微調整が必要な場合は、XML シリアル化を使用する必要があり、このシリアル化テクノロジをサポートする型を自分でデザインする必要があります。

  1. 作成された XML の形状を制御しなければならない強力な理由がない限り、XML シリアル化のために特別に型をデザインすることは避けてください。 このシリアル化テクノロジは、前のセクションで説明したデータ コントラクトのシリアル化よりも優先されます。

    言い換えれば、XML シリアル化で使用する型であることがわかっている場合を除き、System.Runtime.Serialization 名前空間の属性を新しい型に適用しないでください。 System.Xml.Serialization を使用して、作成された XML の形状を制御する方法を次の例に示します。

    Public Class Address2
        ' Supports XML Serialization.
        <System.Xml.Serialization.XmlAttribute()> _
        Public ReadOnly Property Name As String ' Serialize as XML attribute, instead of an element.
            Get
                Return "Poe, Toni"
            End Get
        End Property
        <System.Xml.Serialization.XmlElement(ElementName:="StreetLine")> _
        Public Street As String = "1 Main Street"  ' Explicitly names the element 'StreetLine'.
    End Class
    
    public class Address2
    {
        [System.Xml.Serialization.XmlAttribute] // Serialize as XML attribute, instead of an element.
        public string Name { get { return "Poe, Toni"; } set { } }
        [System.Xml.Serialization.XmlElement(ElementName = "StreetLine")] // Explicitly name the element.
        public string Street = "1 Main Street";        
    }
    
  2. XML シリアル化属性を適用することで提供される、シリアル化された XML の形状をより細かく制御する場合は、IXmlSerializable インターフェイスを実装することを検討してください。 2 つのインターフェイスのメソッド、ReadXml と WriteXml を使用することで、シリアル化された XML ストリームを完全制御できます。 また、XmlSchemaProviderAttribute 属性を適用することで、その型用に生成される XML スキーマを制御することもできます。

6exf3h2k.collapse_all(ja-jp,VS.120).gifランタイム シリアル化のサポート

ランタイム シリアル化は .NET リモート処理で使用されるテクノロジです。 .NET リモート処理を使用して型を変換する場合、ランタイム シリアル化がサポートされていることを確認する必要があります。

ランタイム シリアル化の基本的なサポートは SerializableAttribute 属性を適用して提供できますが、より高度なシナリオでは単純なランタイム シリアル化可能パターン (-ISerializable を実装してシリアル化コンストラクターを指定) を実装することが必要になります。

  1. 使用する型で .NET リモート処理を使用する場合は、ランタイムのシリアル化をサポートすることを検討してください。 たとえば、System.AddIn 名前空間は .NET リモート処理を使用するため、System.AddIn アドイン間で交換されるすべての型でランタイム シリアル化をサポートする必要があります。

    <Serializable()> Public Class Person6 ' Support runtime serialization with the SerializableAttribute.
    
        ' Code not shown.
    End Class
    
    // Apply SerializableAttribute to support runtime serialization.
    [Serializable]
    public class Person6 
    {
        // Code not shown.
    }
    
  2. シリアル化プロセスを完全制御する場合は、ランタイム シリアル化可能パターンを実装することを検討してください。 たとえば、シリアル化または逆シリアル化されたデータを変換したいとします。

    パターンは単純です。 必要な作業は、ISerializable インターフェイスを実装し、オブジェクトを逆シリアル化するときに使用する特別なコンストラクターを指定するだけです。

        ' Implement the ISerializable interface for more control.
        <Serializable()> Public Class Person_Runtime_Serializable
            Implements ISerializable
    
            Private fullNameValue As String
    
            Public Sub New()
                ' empty constructor.
            End Sub
            Protected Sub New(ByVal info As SerializationInfo, _
                              ByVal context As StreamingContext)
                If info Is Nothing Then
                    Throw New System.ArgumentNullException("info")
                    FullName = CType(info.GetValue("name", GetType(String)), String)
                End If
            End Sub
    
            Private Sub GetObjectData(ByVal info As SerializationInfo, _
                                      ByVal context As StreamingContext) _
                                  Implements ISerializable.GetObjectData
                If info Is Nothing Then
                    Throw New System.ArgumentNullException("info")
                    info.AddValue("name", FullName)
                End If
            End Sub
    
            Public Property FullName As String
    
                Get
                    Return fullNameValue
                End Get
                Set(ByVal value As String)
                    fullNameValue = value
    
                End Set
            End Property
    
        End Class
    
    
    // Implement the ISerializable interface for more control.
    [Serializable]
    public class Person_Runtime_Serializable : ISerializable
    {
        string fullName;
    
        public Person_Runtime_Serializable() { }
        protected Person_Runtime_Serializable(SerializationInfo info, StreamingContext context){
            if (info == null) throw new System.ArgumentNullException("info");
            fullName = (string)info.GetValue("name", typeof(string));
        }
        [SecurityPermission(SecurityAction.LinkDemand,
        Flags = SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData(SerializationInfo info,
                StreamingContext context) {
            if (info == null) throw new System.ArgumentNullException("info");
            info.AddValue("name", fullName);
        }
    
        public string FullName
        {
            get { return fullName; }
            set { fullName = value; }
        }
    }
    
  3. このサンプルに示すように、シリアル化コンストラクターを保護し、型と名前を指定した 2 つのパラメーターを用意してください。

    Protected Sub New(ByVal info As SerializationInfo, _
                      ByVal context As StreamingContext)
    
    protected Person_Runtime_Serializable(SerializationInfo info, StreamingContext context){
    
  4. ISerializable メンバーを明示的に実装してください。

    Private Sub GetObjectData(ByVal info As SerializationInfo, _
                              ByVal context As StreamingContext) _
                          Implements ISerializable.GetObjectData
    
    void ISerializable.GetObjectData(SerializationInfo info,
            StreamingContext context) {
    
  5. ISerializable.GetObjectData の実装にはリンク確認要求を適用してください。 こうすることで、完全に信頼できるコア、およびランタイムのシリアライザーだけがメンバーにアクセスできるようになります。

    <Serializable()> Public Class Person_Runtime_Serializable2
        Implements ISerializable
        <SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.SerializationFormatter)> _
        Private Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, _
                                 ByVal context As System.Runtime.Serialization.StreamingContext) _
                             Implements System.Runtime.Serialization.ISerializable.GetObjectData
            ' Code not shown.
        End Sub
    End Class
    
    [SecurityPermission(SecurityAction.LinkDemand,
    Flags = SecurityPermissionFlag.SerializationFormatter)]
    

参照

概念

データ コントラクトの使用

データ コントラクト シリアライザーでサポートされる型

セキュリティとシリアル化

その他の技術情報

データ コントラクト シリアライザー

バイナリ シリアル化

Remote Objects

XML シリアル化および SOAP シリアル化