Pergunta

Usando C# .NET 2.0, tenho uma classe de dados compostos que possui o [Serializable] atributo nele.Estou criando um XMLSerializer class e passando isso para o construtor:

XmlSerializer serializer = new XmlSerializer(typeof(DataClass));

Estou recebendo uma exceção dizendo:

Ocorreu um erro ao refletir o tipo.

Dentro da classe de dados existe outro objeto composto.Isso também precisa ter o [Serializable] atributo, ou por tê-lo no objeto superior, ele o aplica recursivamente a todos os objetos dentro dele?

Foi útil?

Solução

Observe a exceção interna que você está recebendo.Ele informará qual campo/propriedade está tendo problemas para serializar.

Você pode excluir campos/propriedades da serialização xml decorando-os com o [XmlIgnore] atributo.

Eu não acho isso XmlSerializer usa o [Serializable] atributo, então duvido que esse seja o problema.

Outras dicas

Lembre-se de que as classes serializadas devem ter padrão (ou seja,construtores sem parâmetros).Se você não tem nenhum construtor, tudo bem;mas se você tiver um construtor com um parâmetro, precisará adicionar o padrão também.

Eu tive um problema semelhante e descobri que o serializador não conseguia distinguir entre 2 classes que eu tinha com o mesmo nome (uma era uma subclasse da outra).A exceção interna ficou assim:

'Tipos BaseNamespace.Class1' e 'BaseNamespace.SubNamespace.Class1' usam o nome do tipo XML, 'Class1', do namespace ''.Use atributos XML para especificar um nome XML e/ou namespace exclusivo para o tipo.

Onde BaseNamespace.SubNamespace.Class1 é uma subclasse de BaseNamespace.Class1.

O que eu precisava fazer era adicionar um atributo a uma das classes (adicionei na classe base):

[XmlType("BaseNamespace.Class1")]

Observação:Se você tiver mais camadas de classes, precisará adicionar um atributo a elas também.

Também esteja ciente de que XmlSerializer não é possível serializar propriedades abstratas.Veja minha pergunta aqui (ao qual adicionei o código da solução).

Serialização XML e tipos herdados

Razões mais comuns minhas:

 - the object being serialized has no parameterless constructor
 - the object contains Dictionary
 - the object has some public Interface members

Todos os objetos no gráfico de serialização devem ser serializáveis.

Desde XMLSerializer é uma caixa preta, verifique estes links se desejar depurar ainda mais o processo de serialização.

Alterando onde XmlSerializer gera montagens temporárias

COMO:Depurar em um assembly gerado pelo .NET XmlSerializer

Se você precisar lidar com atributos específicos (ou seja,Dicionário ou qualquer classe), você pode implementar o IXmlSerializável interface, o que lhe permitirá mais liberdade ao custo de uma codificação mais detalhada.

public class NetService : IXmlSerializable
{
    #region Data

        public string Identifier = String.Empty;

        public string Name = String.Empty;

        public IPAddress Address = IPAddress.None;
        public int Port = 7777;

    #endregion

    #region IXmlSerializable Implementation

        public XmlSchema GetSchema() { return (null); }

        public void ReadXml(XmlReader reader)
        {
            // Attributes
            Identifier = reader[XML_IDENTIFIER];
            if (Int32.TryParse(reader[XML_NETWORK_PORT], out Port) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_PORT);
            if (IPAddress.TryParse(reader[XML_NETWORK_ADDR], out Address) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_ADDR);
        }

        public void WriteXml(XmlWriter writer)
        {
            // Attributes
            writer.WriteAttributeString(XML_IDENTIFIER, Identifier);
            writer.WriteAttributeString(XML_NETWORK_ADDR, Address.ToString());
            writer.WriteAttributeString(XML_NETWORK_PORT, Port.ToString());
        }

        private const string XML_IDENTIFIER = "Id";

        private const string XML_NETWORK_ADDR = "Address";

        private const string XML_NETWORK_PORT = "Port";

    #endregion
}

Há um interessante artigo, que mostra uma maneira elegante de implementar uma maneira sofisticada de "estender" o XmlSerializer.


O artigo diz:

IXmlSerializable é abordado na documentação oficial, mas a documentação afirma que não se destina ao uso público e não fornece informações além disso.Isso indica que a equipe de desenvolvimento queria se reservar o direito de modificar, desabilitar ou até mesmo remover completamente esse gancho de extensibilidade no futuro.No entanto, desde que você esteja disposto a aceitar essa incerteza e lidar com possíveis mudanças no futuro, não há razão alguma para não tirar vantagem disso.

Por isso, sugiro implementar seu próprio IXmlSerializable classes, a fim de evitar implementações muito complicadas.

... poderia ser simples implementar nosso costume XmlSerializer aula usando reflexão.

Descobri que a classe Dictionary no .Net 2.0 não é serializável usando XML, mas serializa bem quando a serialização binária é usada.

Eu encontrei uma solução alternativa aqui.

Recentemente, obtive isso em uma classe parcial de referência da web ao adicionar uma nova propriedade.A classe gerada automaticamente estava adicionando os seguintes atributos.

    [System.Xml.Serialization.XmlElementAttribute(Order = XX)]

Eu precisava adicionar um atributo semelhante com uma ordem superior ao último na sequência gerada automaticamente e isso corrigiu o problema para mim.

Eu também pensei que o atributo Serializable tinha que estar no objeto, mas a menos que eu seja um novato completo (estou no meio de uma sessão de codificação noturna), o seguinte funciona no SnippetCompilador:

using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Xml.Serialization;

public class Inner
{
    private string _AnotherStringProperty;
    public string AnotherStringProperty 
    { 
      get { return _AnotherStringProperty; } 
      set { _AnotherStringProperty = value; } 
    }
}

public class DataClass
{
    private string _StringProperty;
    public string StringProperty 
    { 
       get { return _StringProperty; } 
       set{ _StringProperty = value; } 
    }

    private Inner _InnerObject;
    public Inner InnerObject 
    { 
       get { return _InnerObject; } 
       set { _InnerObject = value; } 
    }
}

public class MyClass
{

    public static void Main()
    {
        try
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
            TextWriter writer = new StreamWriter(@"c:\tmp\dataClass.xml");
            DataClass clazz = new DataClass();
            Inner inner = new Inner();
            inner.AnotherStringProperty = "Foo2";
            clazz.InnerObject = inner;
            clazz.StringProperty = "foo";
            serializer.Serialize(writer, clazz);
        }
        finally
        {
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
    }

}

Eu imagino que o XmlSerializer esteja usando reflexão sobre as propriedades públicas.

Acabei de receber o mesmo erro e descobri que uma propriedade do tipo IEnumerable<SomeClass> era o problema.Parece que IEnumerable não pode ser serializado diretamente.

Em vez disso, pode-se usar List<SomeClass>.

Tive uma situação em que a Ordem era a mesma para dois elementos seguidos

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]

....algum código ...

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]

Quando alterei o código para aumentar a ordem em um para cada nova propriedade na classe, o erro desapareceu.

Observe também que você não pode serializar controles da interface do usuário e que qualquer objeto que você deseja passar para a área de transferência deve ser serializável, caso contrário não poderá ser passado para outros processos.

Eu tenho usado o NetDataSerialiser Classe para serializar minhas classes de domínio. Classe NetDataContractSerializer.

As classes de domínio são compartilhadas entre cliente e servidor.

[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

//Ou

Xmlignore] string [] strfielsName {get; set;}

Eu tive o mesmo problema e no meu caso o objeto tinha um ReadOnlyCollection.Uma coleção deve implementar o método Add para ser serializável.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top