Compartilhar via


Designer Serialization Overview

Com o designer de serialização pode persistir o estado de seus componentes em tempo de design ou tempo de execução.

Serialização de objetos

O .NET Framework oferece suporte a vários tipos de serialização, como geração de código, SOAP serialização, serialização binária e serialização de XML.

O Designer de serialização é uma forma especial de serialização que envolve o tipo de persistência do objeto geralmente associado a ferramentas de desenvolvimento. O Designer de Serialização é o processo de conversão de um objeto gráfico em um arquivo de origem que posteriormente pode ser usado para recuperar o objeto gráfico. Um arquivo de origem pode conter código, marcação, ou mesmo informações de uma tabela SQL. O Designer de serialização funciona para todos os objetos do common language runtime.

O Designer de serialização difere da serialização do objeto típico de várias maneiras:

  • O objeto que executar a serialização é separado do objeto de tempo de execução, para que a lógica de tempo de design que pode ser removida de um componente.

  • O esquema de serialização foi desenvolvido sob a suposição de que o objeto será criado em um estado totalmente inicializado e então modificado por meio da propriedade e chamadas de método durante a desserialização.

  • Propriedades de um objeto que possuem valores que nunca foram definidas no objeto não são serializadas. Por outro lado, o fluxo de desserialização não pode inicializar todos os valores de propriedade. Para obter uma descrição mais detalhada das regras de serialização, consulte o "regras de serialização geral" seção mais adiante neste tópico.

  • Ênfase é colocada sobre a qualidade do conteúdo dentro do fluxo de serialização, em vez da serialização completa de um objeto. Se não houver nenhuma maneira definida serializar um objeto, esse objeto será transmitido em vez de gerar uma exceção. O Designer de serialização tem maneiras para serializar um objeto em um formulário simple, legível, em vez de um blob opaco.

  • O fluxo de serialização pode ter mais dados do que é necessário para desserialização. Por exemplo, a serialização de código de origem tem misturado com o código necessário para desserializar um gráfico de objeto de código do usuário. Esse código de usuário deve ser preservado na serialização e desserialização passado.

ObservaçãoObservação

O Designer de serialização pode ser usado em tempo de execução, bem como o tempo de design.

A tabela a seguir mostra as metas de design realizadas com o .NET Framework infra-estrutura do designer de serialização.

Objetivo de design

Descrição

Modular

O processo de serialização pode ser estendido para abranger novos tipos de dados e esses tipos de dados podem fornecer descrições de útil, legíveis de si mesmos.

Facilmente extensível

O processo de serialização pode ser estendido para abranger novos tipos de dados com facilidade.

Formato neutro

Objetos podem participar de vários formatos de arquivo diferente e designer de serialização não está vinculada a um formato de dados específico.

Arquitetura

Arquitetura do Designer de serialização baseia-se em metadados, serializadores e um Gerenciador de serialização. A tabela a seguir descreve a função de cada aspecto da arquitetura.

Aspecto

Descrição

Atributos de metadados

Um atributo é usado para relacionar um tipo t com alguns serializador s. Além disso, a arquitetura oferece suporte a um "Carregando" atributo que pode ser usado para instalar um objeto que pode fornecer serializadores para tipos que não os possuem.

Serializadores

Um serializador é um objeto que pode serializar um tipo específico ou um intervalo de tipos. Há uma classe base para cada formato de dados. Por exemplo, pode haver uma DemoXmlSerializer classe base, que pode converter um objeto em XML. A arquitetura é independente de qualquer formato de serialização específico, e ele também inclui uma implementação dessa arquitetura construído sobre o modelo de objeto de documento de código (CodeDOM).

Gerenciador de serialização

O Gerenciador de serialização é um objeto que fornece um armazenamento de informações para todos os serializadores diversas que são usados para serializar um gráfico de objeto. Um gráfico de 50 objetos pode ter 50 serializadores diferentes, que todos geram seus próprios. O Gerenciador de serialização é usado por esses serializadores para se comunicar entre si.

A ilustração e o procedimento a seguir mostram como os objetos em um gráfico, neste caso a e B, podem ser serializados.

Serializando um gráfico de objeto

A serialização de objetos em um gráfico

  1. Chamador solicita um serializador para o objeto a partir do Gerenciador de serialização:

    MySerializer s = manager.GetSerializer(a);
    
  2. O atributo de metadados do tipo vincula a um serializador do tipo solicitado. Então o chamador pergunta serializador para serializar a:.

    Blob b = s.Serialize(manager, a);
    
  3. O serializador de objeto do serializa a. Para cada objeto ao serializar a encontrar, ele solicita serializadores adicionais do Gerenciador de serialização:

    MySerializer s2 = manager.GetSerializer(b);
    Blob b2 = s2.Serialize(manager, b);
    
  4. O resultado da serialização é retornado ao chamador:

    Blob b = ...
    

Regras de serialização gerais

Geralmente, um componente expõe várias propriedades. Por exemplo, o Windows Forms Button controle tem propriedades como BackColor, ForeColor, e BackgroundImage. Quando você coloca um Button controle em um formulário em um designer e exibir o código gerado, você encontrará apenas um subconjunto das propriedades é mantido no código. Normalmente, essas são as propriedades para o qual você tiver definido explicitamente um valor.

O CodeDomSerializer associados a Button o controle define o comportamento de serialização. A lista a seguir descreve algumas das regras usadas pelo CodeDomSerializer para serializar o valor de uma propriedade:

  • Se a propriedade tiver um DesignerSerializationVisibilityAttribute anexado a ele, o serializador usa isso para determinar se a propriedade é serializada (como Visible ou Hidden) e como serializar (Content).

  • O Visible ou Hidden valores especificam se a propriedade é serializada. O Content valor que especifica como a propriedade é serializada.

  • Para uma propriedade chamada DemoProperty, se o componente implementa um método chamado ShouldSerializeDemoProperty, o ambiente de designer faz uma chamada de ligação tardia para este método para determinar se deseja serializar. Por exemplo, para o BackColor propriedade, o método é chamado ShouldSerializeBackColor.

  • Se a propriedade tiver um DefaultValueAttribute especificado, o valor padrão é comparado com o valor atual no componente. A propriedade é serializada somente se o valor atual é não-padrão.

  • O designer associado ao componente também pode reproduzir uma parte em tomar a decisão de serialização por sombreamento propriedades ou implementando ShouldSerialize métodos propriamente dito.

ObservaçãoObservação

O serializador adia a decisão de serialização para o PropertyDescriptor associados com a propriedade e PropertyDescriptor usa as regras listadas anteriormente.

Se você deseja serializar seu componente de maneira diferente, você pode escrever sua própria classe de serializador deriva de CodeDomSerializer e associá-lo com seu componente usando o DesignerSerializerAttribute.

Implementação de serializador inteligente

Um dos requisitos do design serializador é que, quando um novo formato de serialização é necessária, todos os tipos de dados devem ser atualizados com um atributo de metadados para oferecer suporte a esse formato. No entanto, através do uso de provedores de serialização aliados serializadores usam metadados do objeto genérico, esse requisito pode ser atendido. Esta seção descreve a forma preferida de projetar um serializador para um determinado formato, para que a necessidade de muitos serializadores personalizados é minimizada.

O esquema a seguir define um formato hipotético do XML ao qual um gráfico de objeto serão persistentes.

<TypeName>
    <PropertyName>
        ValueString
    </PropertyName>
</TypeName>

Esse formato é serializado usando uma classe fictício chamada DemoXmlSerializer.

public abstract class DemoXmlSerializer 
{
    public abstract string Serialize(
        IDesignerSerializationManager m, 
        object graph);
}

É importante entender que DemoXmlSerializer é uma classe modular que constrói uma cadeia de caracteres de peças. Por exemplo, o DemoXmlSerializer para o Int32 o tipo de dados retornaria a seqüência de caracteres "23" Quando passado um número inteiro de valor 23.

Provedores de serialização

O exemplo de esquema anterior torna claro que há dois tipos fundamentais sejam tratados:

  • Objetos que possuem propriedades filho.

  • Objetos que podem ser convertidos em texto.

Seria difícil de cada classe de adornam com um serializador personalizado que pode converter essa classe para o texto ou as marcas XML. Provedores de serialização resolvem isso, fornecendo um mecanismo de retorno de chamada no qual um objeto tem a oportunidade de fornecer um serializador para um determinado tipo. Neste exemplo, o conjunto disponível de tipos é restrita pelas seguintes condições:

  • Se o tipo pode ser convertido em uma seqüência de caracteres usando o IConvertible interface, o StringXmlSerializer será usado.

  • Se o tipo não pode ser convertido para uma seqüência de caracteres, mas é pública, e tem um construtor vazio, o ObjectXmlSerializer será usado.

  • Se nenhum deles for true, o provedor de serialização retornará null, indicando que não há nenhum serializador para o objeto.

O exemplo de código a seguir mostra como a chamada resolve serializador o que acontece com esse erro ocorre.

internal class XmlSerializationProvider : IDesignerSerializationProvider 
{
    object GetSerializer(
        IDesignerSerializationManager manager, 
        object currentSerializer, 
        Type objectType, 
        Type serializerType) 
    {

        // Null values will be given a null type by this serializer.
        // This test handles this case.
        if (objectType == null) 
        {
            return StringXmlSerializer.Instance;
        }

        if (typeof(IConvertible).IsSubclassOf(objectType)) 
        {
            return StringXmlSerializer.Instance;
        }

        if (objectType.GetConstructor(new object[]) != null) 
        {
            return ObjectXmlSerializer.Instance;
        }

        return null;
    }
}

Depois de um provedor de serialização é definido, devem ser colocado em uso. O Gerenciador de serialização pode ser fornecido por meio de um provedor de serialização do AddSerializationProvider método, mas isso requer que esta chamada feita o Gerenciador de serialização. Um provedor de serialização pode ser adicionado automaticamente para o Gerenciador de serialização, adicionando um DefaultSerializationProviderAttribute para o serializador. Este atributo requer que o provedor de serialização tem um construtor público, vazio. O exemplo de código a seguir mostra a alteração necessária para DemoXmlSerializer.

[DefaultSerializationProvider(typeof(XmlSerializationProvider))]
public abstract class DemoXmlSerializer 
{
}

Agora, sempre que o Gerenciador de serialização é solicitado para qualquer tipo de DemoXmlSerializer, o provedor de serialização padrão será adicionado ao Gerenciador de serialização se ele não tem aconteceu.

Serializadores

O exemplo de DemoXmlSerializer classe tem duas classes do serializador concreto denominados StringXmlSerializer e ObjectXmlSerializer. O exemplo de código a seguir mostra a implementação de StringXmlSerializer.

internal class StringXmlSerializer : DemoXmlSerializer
{
    internal StringXmlSerializer Instance = new StringXmlSerializer();

    public override string Serialize(
        IDesignerSerializationManager m, 
        object graph) 
    {

        if (graph == null) return string.Empty;

        IConvertible c = graph as IConvertible;
        if (c == null) 
        {
            // Rather than throwing exceptions, add a list of errors 
            // to the serialization manager.
            m.ReportError("Object is not IConvertible");
            return null;
        }

    return c.ToString(CultureInfo.InvariantCulture);
    }
}

O ObjectXmlSerializer implementação é mais envolvida, porque é necessário enumerar as propriedades públicas do objeto. O exemplo de código a seguir mostra a implementação de ObjectXmlSerializer.

internal class ObjectXmlSerializer : DemoXmlSerializer 
{
    internal ObjectXmlSerializer Instance = new ObjectXmlSerializer();

    public override string Serialize(
        IDesignerSerializationManager m, 
        object graph) 
    {

        StringBuilder xml = new StringBuilder();
        xml.Append("<");
        xml.Append(graph.GetType().FullName);
        xml.Append(">");

        // Now, walk all the properties of the object.
        PropertyDescriptorCollection properties;
        Property p;

        properties = TypeDescriptor.GetProperties(graph);

        foreach(p in properties) 
        {
            if (!p.ShouldSerializeValue(graph)) 
            {
                continue;
            }

            object value = p.GetValue(graph);
            Type valueType = null;
            if (value != null) valueType = value.GetType();

            // Get the serializer for this property
            DemoXmlSerializer s = m.GetSerializer(
                valueType, 
                typeof(DemoXmlSerializer)) as DemoXmlSerializer;

            if (s == null) 
            {
                // Because there is no serializer, 
                // this property must be passed over.  
                // Tell the serialization manager
                // of the error.
                m.ReportError(string.Format(
                    "Property {0} does not support XML serialization",
                    p.Name));
                continue;
            }

            // You have a valid property to write.
            xml.Append("<");
            xml.Append(p.Name);
            xml.Append(">");

            xml.Append(s.Serialize(m, value);

            xml.Append("</");
            xml.Append(p.Name);
            xml.Append(">");
        }

        xml.Append("</");
        xml.Append(graph.GetType().FullName);
        xml.Append(">");
        return xml.ToString();
    }
}

ObjectXmlSerializerinvoca a outros serializadores para cada valor de propriedade. Isso tem duas vantagens. Primeiro, ele permite que ObjectXmlSerializer a ser muito simples. Segundo, ele fornece um ponto de extensibilidade para tipos de terceiros. Se ObjectXmlSerializer é apresentada com um tipo que não podem ser gravadas por qualquer um desses serializadores um serializador personalizado pode ser fornecido para o tipo.

Uso

Para usar esses novos serializadores, uma instância de IDesignerSerializationManager deve ser criado. Nessa instância, você pode pede um serializador e pedir o serializador para serializar objetos. Para o exemplo de código a seguir, Rectangle será usado para um objeto serializar, pois esse tipo tem um construtor vazio e tem quatro propriedades que ofereçam suporte a IConvertible. Em vez de implementar IDesignerSerializationManager você mesmo, você pode usar a implementação oferecida pelo DesignerSerializationManager.

Rectangle r = new Rectangle(5, 10, 15, 20);
DesignerSerializationManager m = new DesignerSerializationManager();
DemoXmlSerializer x = (DemoXmlSerializer)m.GetSerializer(
    r.GetType(), typeof(DemoXmlSerializer);

string xml = x.Serialize(m, r);

Isso criaria o XML a seguir.

<System.Drawing.Rectangle>
<X>
5
</X>
<Y>
10
</Y>
<Width>
15
</Width>
<Height>
15
</Height>
</System.Drawing.Rectangle>
ObservaçãoObservação

O XML não é recuado. Isso poderia ser facilmente conseguido por meio de Context propriedade em IDesignerSerializationManager. Cada nível do serializador poderia adicionar um objeto na pilha de contexto que contém o atual nível de recuo e cada serializador poderia procurar o objeto na pilha e usá-lo para fornecer um recuo.

Consulte também

Referência

IDesignerSerializationManager

DesignerSerializationManager

DefaultSerializationProviderAttribute

IConvertible

CodeDomSerializerBase

Outros recursos

Estendendo suporte em tempo de design