Designer Serialization Overview
Com o designer de serialização, você pode manter 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, tais como geração de código, serialização SOAP, 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 de 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 é diferente de serialização do objeto típico de várias maneiras:
O objeto realizar a serialização é separado do objeto de tempo de execução, para que a lógica de tempo de design 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 invocações do 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, é possível que o fluxo de desserialização não inicializar todos os valores de propriedade.Para obter uma descrição mais detalhada das regras de serialização, consulte a seção "Regras de serialização geral" 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 há nenhuma maneira definida para serializar um objeto, esse objeto será passado 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ção |
---|
O Designer de serialização pode ser usado em tempo de execução, bem como em tempo de design. |
A tabela a seguir mostra as metas de design realizadas com o .NET Framework infra-estrutura do designer de serialização.
Meta 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 úteis e 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 o 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 da 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 atributo de "inicialização" que pode ser usado para instalar um objeto que pode fornecer serializadores para tipos que não sem encontrem. |
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 que pode converter um objeto no XML base.A arquitetura é independente de qualquer formato de serialização específicas e também inclui uma implementação dessa arquitetura baseado no 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 seu próprios saída.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.
Serialização de objetos em um gráfico
Chamador solicita um serializador para o objeto a partir do Gerenciador de serialização:
MySerializer s = manager.GetSerializer(a);
O atributo de metadados do tipo vincula a um serializador do tipo solicitado.Chamador pede serializador para serializar a:.
Blob b = s.Serialize(manager, a);
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);
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ção |
---|
O serializador adia a decisão de serialização do 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 que deriva de CodeDomSerializer e associá-la ao 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 se criar um serializador para um determinado formato de modo 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 cria uma seqüência de caracteres a partir de pedaços.Por exemplo, o DemoXmlSerializer para o Int32 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 deve ser tratado:
Objetos que possuem propriedades filho.
Objetos que podem ser convertidos em texto.
Seria difícil para adornam todas as classes com um serializador personalizado que pode converter essa classe para o texto ou as marcas XML.Provedores de serialização solucionar esse problema, 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 para 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;
}
}
Assim que 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 o Gerenciador de serialização feita essa chamada.Um provedor de serialização pode ser adicionado automaticamente ao gerente 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 um gerente 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 ocorreu já.
Serializadores
O exemplo de DemoXmlSerializer classe tem duas classes de concreto serializador chamados 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 da propriedade.Isso tem duas vantagens.Primeiro, ele permite que ObjectXmlSerializer ser muito simples.Em segundo lugar, ele fornece um ponto de extensibilidade para tipos de terceiros.Se ObjectXmlSerializer é apresentado com um tipo que não podem ser gravadas por qualquer um desses serializadores, um serializador personalizado pode ser fornecido para esse tipo.
Uso
Para usar esses novos serializadores, uma instância de IDesignerSerializationManager deve ser criado.Nessa instância, você pode pede um serializador e pergunta o serializador para serializar os objetos.Para o exemplo de código a seguir, Rectangle será usado para um objeto para serializar, pois esse tipo tem um construtor vazio e tem quatro propriedades que oferecem 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ção |
---|
O XML não é recuado.Isso poderia ser feito facilmente com o 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 pesquisar esse objeto na pilha e usá-lo para fornecer um recuo. |
Consulte também
Referência
DefaultSerializationProviderAttribute