Estou escrevendo código para fazer serialização de XML. Com função abaixo.
public static string SerializeToXml(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, obj);
return writer.ToString();
}
}
Se o argumento for uma instância da classe sem construtor sem parâmetros, lançará uma exceção.
Exceção sem tratamento: System.InvalidOperationException: CSharpConsole.Foo não pode ser serializado porque não possui um construtor sem parâmetros. em System.Xml.Serialization.TypeDesc.CheckSupported () em System.Xml.Serialization.TypeScope.GetTypeDesc (Type type, MemberInfo sourc e, Boolean directReference, Boolean throwOnError) em System.Xml.Serialization.ModelScope.GetTypeModel (Type type, Referência direta booleana) em System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (Tipo de tipo, raiz XmlRootAttribute, String defaultNamespace) em System.Xml.Serialization.XmlSerializer..ctor (Tipo de tipo, String defaultName space) em System.Xml.Serialization. XmlSerializer..ctor (tipo Type)
Por que deve haver um construtor sem parâmetros para permitir que a serialização xml seja bem-sucedida?
EDIT: obrigado pela resposta de cfeduke. O construtor sem parâmetros pode ser privado ou interno.
fonte
XmlSerializer
requer um construtor sem parâmetros padrão para desserialização.Respostas:
Durante a desserialização de um objeto, a classe responsável pela desserialização de um objeto cria uma instância da classe serializada e passa a preencher os campos e propriedades serializados somente depois de adquirir uma instância a ser preenchida.
Você pode criar seu construtor
private
ou,internal
se quiser, desde que não tenha parâmetros.fonte
private
ouinternal
, todas as suas propriedades cujos valores foram serializados devem terpublic
setters.Esta é uma limitação de
XmlSerializer
. Observe queBinaryFormatter
eDataContractSerializer
não exige isso - eles podem criar um objeto não inicializado a partir do éter e inicializá-lo durante a desserialização.Como você está usando xml, considere usar
DataContractSerializer
e marcar sua classe com[DataContract]
/[DataMember
], mas observe que isso altera o esquema (por exemplo, não há equivalente a[XmlAttribute]
- tudo se torna elementos).Atualização: se você realmente quer saber,
BinaryFormatter
et al useFormatterServices.GetUninitializedObject()
para criar o objeto sem chamar o construtor. Provavelmente perigoso; Não recomendo usá-lo com muita frequência ;-p Consulte também as observações no MSDN:Eu tenho meu próprio mecanismo de serialização, mas não pretendo usá-lo
FormatterServices
; Eu gosto de saber que um construtor ( qualquer construtor) realmente executou.fonte
FormatterServices
uso por idadesIXmlSerializable
, mas um: o que acontece depois de o construtor, e b: é muito feio e difícil de obter direito (especialmente desserialização) - Eu recomendo fortemente contra a tentar implementar isso, mas: não vai permitir que você usar construtoresA resposta é: sem nenhuma boa razão.
Ao contrário do nome, a
XmlSerializer
classe é usada não apenas para serialização, mas também para desserialização. Ele executa certas verificações em sua classe para garantir que funcione, e algumas são pertinentes apenas à desserialização, mas as executam de qualquer maneira, porque não sabem o que você pretende fazer posteriormente.A verificação que sua classe falha na aprovação é uma das que são pertinentes apenas à desserialização. Aqui está o que acontece:
Durante a desserialização, a
XmlSerializer
classe precisará criar instâncias do seu tipo.Para criar uma instância de um tipo, um construtor desse tipo precisa ser chamado.
Se você não declarou um construtor, o compilador já forneceu um construtor sem parâmetros padrão, mas se você declarou um construtor, esse é o único construtor disponível.
Portanto, se o construtor que você declarou aceitar parâmetros, a única maneira de instanciar sua classe é invocando o construtor que aceita parâmetros.
No entanto,
XmlSerializer
não é capaz de chamar qualquer construtor, exceto um construtor sem parâmetros, porque não sabe quais parâmetros passar para os construtores que aceitam parâmetros. Portanto, ele verifica se sua classe possui um construtor sem parâmetros e, como não possui, falha.Portanto, se a
XmlSerializer
classe tivesse sido escrita de forma a executar apenas as verificações pertinentes à serialização, sua classe passaria, porque não há absolutamente nada na serialização que torne necessário um construtor sem parâmetros.Como outros já apontaram, a solução rápida para o seu problema é simplesmente adicionar um construtor sem parâmetros. Infelizmente, também é uma solução suja, porque significa que você não pode ter nenhum
readonly
membro inicializado a partir de parâmetros do construtor.Além de tudo isso, a
XmlSerializer
classe poderia ter sido escrita de forma a permitir uma desserialização uniforme de classes sem construtores sem parâmetros. Tudo o que seria necessário seria fazer uso do "The Factory Method Design Pattern" (Wikipedia) . Pelo que parece, a Microsoft decidiu que esse padrão de design é avançado demais para programadores DotNet, que aparentemente não devem ser desnecessariamente confundidos com essas coisas. Portanto, os programadores do DotNet devem se ater melhor aos construtores sem parâmetros, de acordo com a Microsoft.fonte
For no good reason whatsoever,
depois continua:XmlSerializer is not capable of invoking any constructor except a parameterless constructor, because it does not know what parameters to pass to constructors that accept parameters.
Se ele não sabe quais parâmetros passar para um construtor, como saberia quais parâmetros passar para uma fábrica? Ou qual fábrica usar? Não consigo imaginar essa ferramenta mais simples de usar - você deseja que uma classe seja desserializada, deixe o desserializador criar uma instância padrão e preencha cada campo que você marcou. Fácil.Primeiro de tudo, é isso que está escrito na documentação . Eu acho que é um dos campos da sua classe, não o principal - e como você deseja que o desserializador o construa de volta sem a construção sem parâmetros?
Eu acho que existe uma solução alternativa para tornar o construtor privado.
fonte