Compartilhar via


Diretrizes de serialização

Este documento lista as diretrizes a serem consideradas na criação de uma API a ser serializado.

O .NET Framework oferece três tecnologias de serialização principais que são otimizadas para vários cenários de serialização. A tabela a seguir lista essas tecnologias e os principais tipos de estrutura relacionados a elas.

Tecnologia

Classes relevantes

Notas

Serialização do contrato de dados

DataContractAttribute

DataMemberAttribute

DataContractSerializer

NetDataContractSerializer

DataContractJsonSerializer

ISerializable

Persistência geral

Serviços Web

JSON

Serialização XML

XmlSerializer

Formato XML com controle total

Tempo de execução - serialização (binário e SOAP)

SerializableAttribute

ISerializable

BinaryFormatter

SoapFormatter

Comunicação remota .NET

Ao criar novos tipos, você deverá decidir a quais dessas tecnologias, se houver alguma, esses tipos precisam oferecer suporte. As diretrizes a seguir descrevem como fazer essa escolha e como fornecer esse suporte. Essas diretrizes não foram criadas para ajudar você a escolher qual tecnologia de serialização usará na implementação do aplicativo ou da biblioteca. Elas não estão diretamente relacionadas ao design da API e, portanto, não estão dentro do escopo deste tópico.

Diretrizes

  • Pense sobre a serialização ao criar novos tipos.

    A serialização é uma questão de design importante a ser considerada para qualquer tipo, pois os programas talvez precisem persistir ou transmitir instâncias do tipo.

6exf3h2k.collapse_all(pt-br,VS.120).gifEscolhendo a tecnologia de serialização correta que receberá suporte

Qualquer tipo específico pode oferecer suporte a nenhuma, uma ou mais tecnologias de serialização.

  • CONSIDERE o suporte à serialização de contrato de dados se as instâncias do tipo talvez precisem ser persistentes ou usadas nos Serviços Web.

  • CONSIDERE o suporte à serialização XML em vez da ou além da serialização do contrato de dados se você precisar ter mais controle sobre o formato XML gerado quando o tipo for serializado.

    Isso talvez seja necessário em alguns cenários de interoperabilidade no qual você precise usar uma construção XML para a qual não haja suporte na serialização do contrato de dados, por exemplo, para gerar atributos XML.

  • CONSIDERE o suporte à serialização em tempo de execução se as instâncias do tipo precisarem ultrapassar os limites da comunicação remota .NET.

  • EVITE o suporte à serialização em tempo de execução ou à serialização XML apenas por motivos gerais de persistência. Prefira a serialização do contrato de dados em vez disso

6exf3h2k.collapse_all(pt-br,VS.120).gifOferecendo suporte à serialização do contrato de dados

Os tipos podem oferecer suporte à serialização do contrato de dados aplicando o DataContractAttribute ao tipo e o DataMemberAttribute aos membros (campos e propriedades) do tipo.

<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. CONSIDERE marcar os membros de dados do tipo público se o tipo puder ser usado na confiança parcial. Na confiança total, os serializadores do contrato de dados podem serializar e desserializar tipos e membros não públicos, mas somente os membros públicos podem ser serializados e desserializados na confiança parcial.

  2. IMPLEMENTE um getter e um setter em todas as propriedades que têm Data-MemberAttribute. Os serializadores do contrato de dados requerem o getter e o setter para o tipo a ser considerado serializável. Se o tipo não será usado na confiança parcial, um ou ambos os acessadores de propriedade poderão ser não públicos.

    <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. CONSIDERE o uso de retornos de chamada de serialização para a inicialização de instâncias desserializadas.

    Os construtores não são chamados quando os objetos são desserializados. Portanto, qualquer lógica que executada durante a construção normal precisa ser implementada como um dos retornos de chamada de serialização.

    <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 é o atributo de retorno de chamada mais usado. Os outros atributos da família são OnDeserializingAttribute, OnSeralizingAttribute e OnSerializedAttribute. Eles podem ser usados para marcar os retornos de chamada que são executados antes de desserialização, antes da serialização e, por fim, após a serialização, respectivamente.

  4. CONSIDERE o uso do KnownTypeAttribute para indicar os tipos concretos que devem ser usados ao desserializar um gráfico de objeto complexo.

    Por exemplo, se o tipo de um membro de dados desserializado for representado por uma classe abstrata, o serializador precisará das informações de tipo conhecido para decidir qual tipo concreto será instanciado e atribuído ao membro. Se o tipo conhecido não for especificado por meio do atributo, ele precisará ser passado para o serializador explicitamente (você pode fazer isso passando os tipos conhecidos para o construtor do serializador) ou precisará ser especificado no arquivo de configuração.

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

    Nos casos em que a lista de tipos conhecidos não é conhecida estaticamente (quando a classe Person é compilada), KnownTypeAttribute também pode apontar para um método que retorna uma lista de tipos conhecidos em tempo de execução.

  5. Considere a compatibilidade com versões anteriores e posteriores ao criar ou modificar tipos serializáveis.

    Tenha em mente que os fluxos serializados de versões futuras do tipo podem ser desserializados na versão atual de tipo e vice-versa. Verifique se compreendeu que os membros de dados, até mesmo os privados e internos, não podem alterar seus nomes, tipos ou mesmo sua ordem nas versões futuras do tipo, a menos que se tome um cuidado especial para preservar o contrato usando parâmetros explícitos para os atributos do contrato de dados. Teste a compatibilidade da serialização ao fazer alterações nos tipos serializáveis. Tente desserializar a nova versão em uma versão antiga e vice-versa.

  6. CONSIDERE implementar a interface IExtensibleDataObject para permitir o ciclo completo entre diferentes versões do tipo.

    A interface permite que o serializador assegure de que nenhum dado sejam perdido durante o ciclo completo. A propriedade ExtensionData armazena todos os dados da versão futura do tipo desconhecido na versão atual. Quando a versão atual for serializada e desserializada subsequentemente em uma versão futura, os dados adicionais estarão disponíveis no fluxo serializado através do valor de propriedade 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; }
        }
    }
    

    Para obter mais informações, consulte Contratos de dados compatíveis por encaminhamento.

6exf3h2k.collapse_all(pt-br,VS.120).gifSuporte à serialização XML

A serialização do contrato de dados é a tecnologia de serialização principal (padrão) do .NET Framework, mas há situações de serialização para as quais a serialização do contrato de dados não oferece suporte. Por exemplo, ela não fornece controle total sobre o formato XML gerado ou consumido pelo serializador. Se esse controle fino for necessário, a serialização XML precisará ser usada, e você precisará criar seus tipos para oferecer suporte essa tecnologia de serialização.

  1. EVITE criar os tipos especificamente para a Serialização XML, a menos que você tenha um motivo muito forte para controlar o formato do XML gerado Essa tecnologia de serialização foi substituída pela serialização do contrato de dados abordada na seção anterior.

    Em outras palavras, não aplique atributos do namespace System.Runtime.Serialization a novos tipos, a menos que você saiba que o tipo será usado com a Serialização XML. O exemplo a seguir mostra como System.Xml.Serialization pode ser usado para controlar o formato do XML gerado.

    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. CONSIDERE implementar a interface IXmlSerializable se quiser ainda mais controle sobre o formato do XML serializado do que o que é oferecido aplicando os atributos de Serialização XML. Dois métodos da interface ReadXmle WriteXml permitem que você controle totalmente o fluxo XML serializável. Você também pode controlar o esquema XML gerado para o tipo aplicando o atributo XmlSchemaProviderAttribute.

6exf3h2k.collapse_all(pt-br,VS.120).gifSuporte à serialização em tempo de execução

A serialização em tempo de execução é uma tecnologia usada pela comunicação remota .NET. Se você considerar que os tipos serão transportados por meio da comunicação remota .NET, será necessário verificar se eles oferecem suporte à serialização em tempo de execução.

O suporte básico da serialização em tempo de execução pode ser fornecido aplicando o atributo SerializableAttribute, e os cenários mais avançados envolvem a implementação de um padrão serializável de tempo de execução simples (implemente -ISerializable e forneça um construtor de serialização).

  1. CONSIDERE o suporte à serialização em tempo de execução se os tipos forem usados com a comunicação remota .NET. Por exemplo, o namespace System.AddIn usa a comunicação remota .NET e, portanto, todos os tipos trocados entre os suplementos System.AddIn precisam oferecer suporte à serialização em tempo de execução.

    <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. CONSIDERE a implementação do padrão serializável em tempo de execução se quiser controle completo sobre o processo de serialização. Por exemplo, se você quiser transformar os dados à medida que eles forem serializados ou desserializados.

    O padrão é muito simples. Tudo o que você precisa fazer é implementar a interface ISerializable e fornecer um construtor especial que é usado quando o objeto é desserializado.

        ' 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. PROTEJA o construtor de serialização e forneça dois parâmetros tipados e nomeados exatamente conforme mostrado no exemplo aqui.

    Protected Sub New(ByVal info As SerializationInfo, _
                      ByVal context As StreamingContext)
    
    protected Person_Runtime_Serializable(SerializationInfo info, StreamingContext context){
    
  4. IMPLEMENTE os membros ISerializable explicitamente.

    Private Sub GetObjectData(ByVal info As SerializationInfo, _
                              ByVal context As StreamingContext) _
                          Implements ISerializable.GetObjectData
    
    void ISerializable.GetObjectData(SerializationInfo info,
            StreamingContext context) {
    
  5. APLIQUE uma demanda de link para a implementação de ISerializable.GetObjectData. Isso garantirá que o somente núcleo completamente confiável e o serializador em tempo de execução terão acesso ao membro.

    <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)]
    

Consulte também

Conceitos

Usando contratos de dados

Tipos com suporte fornecido pelo serializador de contrato de dados

Segurança e serialização

Outros recursos

Serializador de contrato de dados

Serialização binária

Remote Objects

Serialização XML e SOAP