Como eu desaponto um arquivo XML em uma classe com uma propriedade somente leitura?
-
02-07-2019 - |
Pergunta
Eu tenho uma classe que estou usando como uma classe de configurações que é serializada em um arquivo XML que os administradores podem editar para alterar as configurações no aplicativo. (As configurações são um pouco mais complexas que o app.config permite.)
Estou usando a classe XMLSerializer para deseralizar o arquivo XML e quero que ele seja capaz de definir a classe de propriedade, mas não quero que outros desenvolvedores usem a classe/montagem para poder definir/alterar a propriedade através do código. Posso fazer isso acontecer com a classe XMLSerializer?
Para adicionar mais alguns detalhes: esta classe em particular é uma coleção e, de acordo com o FXCOP, a classe XMLSerializer possui suporte especial para a dessertação de coleções somente leitura, mas não consegui encontrar mais informações. Os detalhes exatos sobre a regra que isso viola é:
Propriedades que as coleções de retorno devem ser somente leitura para que os usuários não possam substituir completamente a loja de apoio. Os usuários ainda podem modificar o conteúdo da coleção chamando métodos relevantes na coleção. Observe que a classe XMLSerializer possui suporte especial para a Deserializing Somente Coleções de leitura. Consulte a visão geral do XMLSerializer para obter mais informações.
É exatamente isso que eu quero, mas como isso faz isso?
Editar: Ok, acho que estou ficando um pouco louco aqui. No meu caso, tudo o que eu precisava fazer era inicializar o objeto de coleta no construtor e, em seguida, remover o criador de propriedades. Em seguida, o objeto XMLSerializable realmente sabe usar as propriedades Add/AddRange e Indexer no objeto de coleta. O seguinte realmente funciona!
public class MySettings
{
private Collection<MySubSettings> _subSettings;
public MySettings()
{
_subSettings = new Collection<MySubSettings>();
}
public Collection<MySubSettings> SubSettings
{
get { return _subSettings; }
}
}
Solução
Você precisa usar um tipo de lista mutável, como Arraylist (ou Ilist IIRC).
Outras dicas
@Rob Cooper acertou, basta implementar o Iserializable Interface e você poderá ter controle personalizado sobre como sua classe serializa e Deserialzes e definir os campos manualmente. É um pouco mais de trabalho nas pernas, mas atingirá o objetivo desejado. Boa sorte.
Eu não acho que você possa usar a serialização automática, pois a propriedade é apenas leitura.
Meu curso de ação seria implementar o Iserializable Interface e faça isso manualmente. Você poderá definir os valores internos daqui.
No entanto, se seus subobjetos (que são expostos apenas como leitura) podem cuidar de serializar-se, tudo deve funcionar.
Eu acho que a regra que o FXCOP está gemendo é que você tem algo como:
public List<MyObject> Collection
{
get { return _collection; }
set { _collection = value; }
}
Não é? Caso contrário, você pode colar algum código para que eu possa ver o que exatamente você está fazendo? Existem várias maneiras de fazer todas as opções acima :)
A resposta de @Leppie foi realmente a mais próxima. Este é o texto relevante real na documentação do XMLSerializer e veja minha edição à pergunta acima para obter mais detalhes:
O XMLSerializer fornece um tratamento especial para classes que implementam ienumerable ou icollection. Uma classe que implementa o IEnumerable deve implementar um método de adição público que pegue um único parâmetro. O parâmetro do método ADD deve ser do mesmo tipo que é retornado da propriedade atual no valor retornado do getenumerator ou uma das bases desse tipo. Uma classe que implementa o ICOLLECTION (como a coleta), além do IEnumerable, deve ter uma propriedade indexada por itens públicos (indexador em C#) que leva um número inteiro e deve ter uma propriedade de contagem pública do tipo inteiro. O parâmetro do método Add deve ser o mesmo tipo que é retornado da propriedade do item ou de uma das bases desse tipo. Para classes que implementam o ICOLLECTION, os valores a serem serializados são recuperados da propriedade de itens indexados, não chamando o Getenumerator.