CA2240: ISerializable を正しく実装します

TypeName

ImplementISerializableCorrectly

CheckId

CA2240

分類

Microsoft.Usage

互換性に影響する変更点

なし

原因

外部から参照できる型が ISerializable インターフェイスに適用でき、次のいずれかの条件に当てはまります。

  • 型は ISerializable.GetObjectData メソッドを継承しますがオーバーライドしていません。また、NonSerializedAttribute 属性でマークされていないインスタンス フィールドを型で宣言しています。

  • 型はシールされていません。また、外部から参照できませんがオーバーライドできる GetObjectData メソッドを型で実装しています。

規則の説明

ISerializable フィールドを継承する型で宣言されているインスタンス フィールドは、シリアル化プロセスに自動的には含まれません。フィールドを含めるには、型で GetObjectData メソッドとシリアル化コンストラクターを実装します。フィールドをシリアル化しない場合、フィールドに NonSerializedAttribute 属性を適用し、シリアル化しないことを明示します。

シールされない型の場合、GetObjectData メソッドの実装は外部から参照できるようにします。そのため、メソッドは、派生型から呼び出すことができ、オーバーライドされます。

違反の修正方法

この規則違反を修正するには、GetObjectData メソッドを外部から参照できるようにし、オーバーライドできるようにします。また、すべてのインスタンス フィールドをシリアル化プロセスに含めるか、NonSerializedAttribute 属性で明示的にマークします。

警告を抑制する状況

この規則による警告は抑制しないでください。

使用例

この規則に違反する、2 つのシリアル化できる型を次の例に示します。

Imports System
Imports System.Security.Permissions
Imports System.Runtime.Serialization

Namespace Samples1

    ' Violates this rule
    <Serializable()> _
    Public Class Book
        Implements ISerializable

        Private ReadOnly _Title As String 

        Public Sub New(ByVal title As String)
            If (title Is Nothing) Then Throw New ArgumentNullException("title")
            _Title = title
        End Sub 

        Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            If (info Is Nothing) Then Throw New ArgumentNullException("info")

            _Title = info.GetString("Title")
        End Sub 

        Public ReadOnly Property Title() As String 
            Get 
                Return _Title
            End Get 
        End Property

        <SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.SerializationFormatter)> _
        Public Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext) _
            Implements ISerializable.GetObjectData

            If (info Is Nothing) Then Throw New ArgumentNullException("info")

            info.AddValue("Title", _Title)
        End Sub 
    End Class 

    ' Violates this rule
    <Serializable()> _
    Public Class LibraryBook
        Inherits Book

        Private ReadOnly _CheckedOut As Date 

        Public Sub New(ByVal text As String, ByVal checkedOut As Date)
            MyBase.New(text)
            _CheckedOut = checkedOut
        End Sub 

        Public ReadOnly Property CheckedOut() As Date 
            Get 
                Return _CheckedOut
            End Get 
        End Property 

    End Class 
End Namespace
using System;
using System.Security.Permissions;
using System.Runtime.Serialization;

namespace Samples1
{
    // Violates this rule
    [Serializable]
    public class Book : ISerializable
    {
        private readonly string _Text;

        public Book(string text)
        {
            if (text == null)
                throw new ArgumentNullException("text");

            _Text = text;
        }

        protected Book(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                throw new ArgumentNullException("info");

            _Text = info.GetString("Text");
        }

        public string Text
        {
            get { return _Text; }
        }

        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                throw new ArgumentNullException("info");

            info.AddValue("Text", _Text);
        }
    }

    // Violates this rule
    [Serializable]
    public class LibraryBook : Book
    {
        private readonly DateTime _CheckedOut;

        public LibraryBook(string text, DateTime checkedOut)
            : base(text)
        {
            _CheckedOut = checkedOut;
        }

        public DateTime CheckedOut
        {
            get { return _CheckedOut; }
        }
    }
}
using namespace System;
using namespace System::Security::Permissions;
using namespace System::Runtime::Serialization;

namespace Samples1 
{
    // Violates this rule
    [Serializable]
    public ref class Book : ISerializable
    {
    private:
        initonly String^ _Title;

    public: 
        Book(String^ title)
        {
            if (title == nullptr)
                throw gcnew ArgumentNullException("title");

            _Title = title;
        }

        property String^ Title
        {
            String^ get()
            {
                return _Title;
            }
        }

    protected: 
        Book(SerializationInfo^ info, StreamingContext context)
        {
            if (info == nullptr)
                throw gcnew ArgumentNullException("info");

            _Title = info->GetString("Title");
        }

    private:
        [SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::SerializationFormatter)]
        void virtual GetObjectData(SerializationInfo^ info, StreamingContext context) sealed = ISerializable::GetObjectData
        {
            if (info == nullptr)
                throw gcnew ArgumentNullException("info");

            info->AddValue("Title", _Title);
        }
    };

    // Violates this rule
    [Serializable]
    public ref class LibraryBook : Book
    {
        initonly DateTime _CheckedOut;

    public:
        LibraryBook(String^ title, DateTime checkedOut) : Book(title)
        {
            _CheckedOut = checkedOut;
        }

        property DateTime CheckedOut
        {
            DateTime get()
            {
                return _CheckedOut;
            }
        }
    };
}

Book クラスでオーバーライド可能な [ISerializable.GetObjectData] を実装し、Library クラスで [ISerializable.GetObjectData] を実装することによって上記の 2 つの違反を修正する例を次に示します。

Imports System
Imports System.Security.Permissions
Imports System.Runtime.Serialization

Namespace Samples2

    <Serializable()> _
    Public Class Book
        Implements ISerializable

        Private ReadOnly _Title As String 

        Public Sub New(ByVal title As String)
            If (title Is Nothing) Then Throw New ArgumentNullException("title")
            _Title = title
        End Sub 

        Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            If (info Is Nothing) Then Throw New ArgumentNullException("info")

            _Title = info.GetString("Title")
        End Sub 

        Public ReadOnly Property Title() As String 
            Get 
                Return _Title
            End Get 
        End Property

        <SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.SerializationFormatter)> _
        Protected Overridable Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext) _
            Implements ISerializable.GetObjectData

            If (info Is Nothing) Then Throw New ArgumentNullException("info")

            info.AddValue("Title", _Title)
        End Sub 
    End Class


    <Serializable()> _
    Public Class LibraryBook
        Inherits Book

        Private ReadOnly _CheckedOut As Date 

        Public Sub New(ByVal text As String, ByVal checkedOut As Date)
            MyBase.New(text)
            _CheckedOut = checkedOut
        End Sub 

        Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            MyBase.New(info, context)

            _CheckedOut = info.GetDateTime("CheckedOut")
        End Sub 

        Public ReadOnly Property CheckedOut() As Date 
            Get 
                Return _CheckedOut
            End Get 
        End Property

        <SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.SerializationFormatter)> _
        Protected Overrides Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, _
                                              ByVal context As System.Runtime.Serialization.StreamingContext)

            MyBase.GetObjectData(info, context)

            info.AddValue("CheckedOut", _CheckedOut)
        End Sub 
    End Class 
End Namespace
using System;
using System.Security.Permissions;
using System.Runtime.Serialization;

namespace Samples2
{
    [Serializable]
    public class Book : ISerializable
    {
        private readonly string _Title;

        public Book(string title)
        {
            if (title == null)
                throw new ArgumentNullException("title");

            _Title = title;
        }

        protected Book(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                throw new ArgumentNullException("info");

            _Title = info.GetString("Title");
        }

        public string Title
        {
            get { return _Title; }
        }

        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
        protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Title", _Title);
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                throw new ArgumentNullException("info");

            GetObjectData(info, context);
        }
    }

    [Serializable]
    public class LibraryBook : Book
    {
        private readonly DateTime _CheckedOut;

        public LibraryBook(string title, DateTime checkedOut)
            : base(title)
        {
            _CheckedOut = checkedOut;
        }

        protected LibraryBook(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            _CheckedOut = info.GetDateTime("CheckedOut");
        }

        public DateTime CheckedOut
        {
            get { return _CheckedOut; }
        }

        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
        protected override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);

            info.AddValue("CheckedOut", _CheckedOut);
        }
    }
}
using namespace System;
using namespace System::Security::Permissions;
using namespace System::Runtime::Serialization;

namespace Samples2 
{
    [Serializable]
    public ref class Book : ISerializable
    {
    private:
        initonly String^ _Title;

    public: 
        Book(String^ title)
        {
            if (title == nullptr)
                throw gcnew ArgumentNullException("title");

            _Title = title;
        }

        property String^ Title
        {
            String^ get()
            {
                return _Title;
            }
        }

    protected: 
        Book(SerializationInfo^ info, StreamingContext context)
        {
            if (info == nullptr)
                throw gcnew ArgumentNullException("info");

            _Title = info->GetString("Title");
        }

        [SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::SerializationFormatter)]
        void virtual GetObjectData(SerializationInfo^ info, StreamingContext context) = ISerializable::GetObjectData
        {
            if (info == nullptr)
                throw gcnew ArgumentNullException("info");

            info->AddValue("Title", _Title);
        }
    };

    [Serializable]
    public ref class LibraryBook : Book
    {
        initonly DateTime _CheckedOut;

    public:
        LibraryBook(String^ title, DateTime checkedOut) 
            : Book(title)
        {
            _CheckedOut = checkedOut;
        }

        property DateTime CheckedOut
        {
            DateTime get()
            {
                return _CheckedOut;
            }
        }

    protected: 
        LibraryBook(SerializationInfo^ info, StreamingContext context) : Book(info, context)
        {
            _CheckedOut = info->GetDateTime("CheckedOut");
        }

        [SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::SerializationFormatter)]
        void virtual GetObjectData(SerializationInfo^ info, StreamingContext context) override
        {
            Book::GetObjectData(info, context);
            info->AddValue("CheckedOut", _CheckedOut);
        }
    };
}

関連規則

CA2236: ISerializable 型で基本クラス メソッドを呼び出します

CA2229: シリアル化コンストラクターを実装します

CA2238: シリアル化メソッドを正しく実装します

CA2235: すべてのシリアル化不可能なフィールドを設定します

CA2237: ISerializable 型を SerializableAttribute に設定します

CA2239: オプションのフィールドに逆シリアル化メソッドを指定します

CA2120: シリアル化コンストラクターをセキュリティで保護します