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?

leora
fonte

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.

Lamar
fonte
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.

Jeremy McGee
fonte
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.

Dennis Calla
fonte
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
7

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

Serialização XML e tipos herdados

Rob Cooper
fonte
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
Stefan Michev
fonte
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.

Luca
fonte
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 .

Charlie Salts
fonte
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.

LepardUK
fonte
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>.

jkokorian
fonte
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.

Darren
fonte
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.

Jeremy Brown
fonte
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; }
Iqra.
fonte
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.

Phil Wright
fonte
0

Eu tenho usado a NetDataSerialiserclasse para serializar minhas classes de domínio. Classe NetDataContractSerializer .

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

Peter Mortensen
fonte
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.

Curious Dev
fonte
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");
    }
}
chxzy
fonte
0
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

Ou

[XmlIgnore]
string [] strFielsName {get;set;}
Kiran.Bakwad
fonte