XmlSerializer - Ocorreu um erro ao refletir o tipo
-
09-06-2019 - |
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?
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).
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.
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.