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.