XmlSerializer - Ocorreu um erro ao refletir o tipo


332

Usando o C # .NET 2.0, tenho uma classe de dados composta que possui o [Serializable]atributo. Estou criando uma XMLSerializerclasse 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, há outro objeto composto. Isso também precisa ter o [Serializable]atributo ou, ao tê-lo no objeto superior, aplica-o recursivamente a todos os objetos internos?

Respostas:


413

Veja 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

XmlSerializernão usa o [Serializable]atributo, então duvido que esse seja o problema.


11
Meu objeto tinha um campo Uri, o que causou essa exceção; a classe Uri não possui um construtor sem parâmetros. Obrigado pela dica.
— Ford

10
Me deparei com isso com uma pesquisa no google - meu problema específico era ter uma propriedade na minha classe "a ser serializada" como IListquando precisava ser List.
— Paul Aldred-Bann

7
Como se olha para uma "exceção interna"?
— David

7
ou adicione '@exception' a um relógio
— arolson101

19
Obrigado, esta resposta me ajudou. Inicialmente, observei a exceção interna e vi a menção da classe principal. Mas percebi que poderia me aprofundar nas inexceções das inrexceções e, eventualmente, em cinco níveis abaixo, encontrei o problema. Eu tive aulas conflitantes. Obrigado.
— Louis van Tonder

111

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


4
Obrigado pela lembrança! Eu odeio que este seja um erro de tempo de execução com pouca explicação.
— precisa

Eu continuo cometendo esse erro repetidamente. obrigado por me lembrar de usar um construtor sem parâmetros ^^
— aZtraL-EnForceR

25

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

'Types BaseNamespace.Class1' e 'BaseNamespace.SubNamespace.Class1' usam o nome do tipo XML, 'Class1', do namespace ''. Use atributos XML para especificar um nome XML exclusivo e / ou espaço para nome 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 à classe base):

[XmlType("BaseNamespace.Class1")]

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


Isso corrigiu o problema para mim, obrigado, +1; Eu tinha uma configuração semelhante com vários objetos Processor *, cada um com uma classe interna Config. O tempo de execução não conseguiu distinguir entre SomeNS.Processor1.Config e SomeNS.Processor2.Config.
— precisa saber é o seguinte


6

Razões mais comuns por mim:

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


5

Se você precisar lidar com atributos específicos (por exemplo, Dictionary ou qualquer classe), poderá implementar a interface IXmlSerialiable , que 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 artigo interessante , 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 declara 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 reservar o direito de modificar, desativar ou mesmo remover completamente esse gancho de extensibilidade no caminho. No entanto, desde que você esteja disposto a aceitar essa incerteza e lidar com possíveis mudanças no futuro, não há motivo para não tirar proveito disso.

Por isso, sugiro implementar suas próprias IXmlSerializableclasses, a fim de evitar implementações muito complicadas.

... poderia ser simples implementar nossa XmlSerializerclasse personalizada usando reflexão.


4

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

Encontrei um trabalho por aqui .


3

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 um pedido superior ao último na sequência gerada automaticamente e isso foi corrigido para mim.


3

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

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


2

Eu também pensei que o atributo Serializable tinha que estar no objeto, mas, a menos que eu esteja sendo um noob completo (estou no meio de uma sessão de codificação tarde da noite), os seguintes trabalhos do SnippetCompiler :

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 imaginaria que o XmlSerializer está usando a reflexão sobre as propriedades públicas.


1

Eu 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 incrementar o pedido em um para cada nova propriedade da classe, o erro desapareceu.


1

Eu estava recebendo o mesmo erro quando criei uma propriedade com um tipo de dados - Type. Por isso, estava recebendo um erro - houve um erro ao refletir o tipo. Continuei verificando a 'InnerException' de todas as exceções do dock de depuração e obtive o nome do campo específico (que era Type) no meu caso. A solução é a seguinte:

    [XmlIgnore]
    public Type Type { get; set; }

0

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 transmitido para outros processos.



0

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.


Esta não é uma resposta adequada para a pergunta. Já existem outras 15 respostas sobre esta questão. Se você acha que sua resposta é melhor que as outras, forneça mais detalhes. O fornecimento de alguns trechos de código e saída sempre ajuda os usuários. Antes de postar suas respostas considere a leitura -> stackoverflow.com/help/how-to-answer
— Amit Phaltankar

0

Eu tenho uma solução um pouco diferente de tudo descrito aqui até agora, portanto, para qualquer civilização futura, aqui está a minha!

Eu havia declarado um tipo de dados "time" como o tipo original era a TimeSpane, posteriormente, alterado para a String:

[System.Xml.Serialization.XmlElementAttribute(DataType="time", Order=3)]

no entanto, o tipo real era uma string

public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}

removendo a DateTypepropriedade Xmlpode ser serializada

[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}

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

Ou

[XmlIgnore]
string [] strFielsName {get;set;}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.