CA2240: Implementar ISerializable corretamente

Item Valor
RuleId CA2240
Categoria Microsoft.Usage
Alteração da falha Sem interrupção

Causa

Um tipo visível externamente pode ser atribuído à interface System.Runtime.Serialization.ISerializable e uma das seguintes condições é verdadeira:

Descrição da regra

Os campos de instância declarados em um tipo que herda a interface System.Runtime.Serialization.ISerializable não são incluídos automaticamente no processo de serialização. Para incluir os campos, o tipo deve implementar o método GetObjectData e o construtor de serialização. Se os campos não devem ser serializados, aplique o atributo NonSerializedAttribute aos campos para indicar explicitamente a decisão.

Em tipos que não são selados, as implementações do método GetObjectData devem ser visíveis externamente. Portanto, o método pode ser chamado por tipos derivados e é substituível.

Como corrigir violações

Para corrigir uma violação dessa regra, deixe o método GetObjectData visível e substituível e verifique se todos os campos de instância estão incluídos no processo de serialização ou marcados explicitamente com o atributo NonSerializedAttribute.

Quando suprimir avisos

Não suprima um aviso nessa regra.

Exemplo 1

O exemplo a seguir mostra dois tipos serializáveis que violam a regra.

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; }
        }
    }
}

Exemplo 2

O exemplo a seguir corrige as duas violações anteriores fornecendo uma implementação substituível de GetObjectData na classe Book e fornecendo uma implementação de GetObjectData na classe Library.

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);
        }
    }
}