Depois que um programador decide implementar IXmlSerializable
, quais são as regras e práticas recomendadas para implementá-lo? Ouvi dizer que GetSchema()
deve retornar null
e ReadXml
deve passar para o próximo elemento antes de retornar. Isso é verdade? E o que dizer WriteXml
- ele deve escrever um elemento raiz para o objeto ou presume-se que a raiz já esteja gravada? Como os objetos filhos devem ser tratados e gravados?
Aqui está uma amostra do que tenho agora. Vou atualizá-lo à medida que obtiver boas respostas.
public class MyCalendar : IXmlSerializable
{
private string _name;
private bool _enabled;
private Color _color;
private List<MyEvent> _events = new List<MyEvent>();
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyCalendar")
{
_name = reader["Name"];
_enabled = Boolean.Parse(reader["Enabled"]);
_color = Color.FromArgb(Int32.Parse(reader["Color"]));
if (reader.ReadToDescendant("MyEvent"))
{
while (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyEvent")
{
MyEvent evt = new MyEvent();
evt.ReadXml(reader);
_events.Add(evt);
}
}
reader.Read();
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("Name", _name);
writer.WriteAttributeString("Enabled", _enabled.ToString());
writer.WriteAttributeString("Color", _color.ToArgb().ToString());
foreach (MyEvent evt in _events)
{
writer.WriteStartElement("MyEvent");
evt.WriteXml(writer);
writer.WriteEndElement();
}
}
}
public class MyEvent : IXmlSerializable
{
private string _title;
private DateTime _start;
private DateTime _stop;
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyEvent")
{
_title = reader["Title"];
_start = DateTime.FromBinary(Int64.Parse(reader["Start"]));
_stop = DateTime.FromBinary(Int64.Parse(reader["Stop"]));
reader.Read();
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("Title", _title);
writer.WriteAttributeString("Start", _start.ToBinary().ToString());
writer.WriteAttributeString("Stop", _stop.ToBinary().ToString());
}
}
XML de amostra correspondente
<MyCalendar Name="Master Plan" Enabled="True" Color="-14069085">
<MyEvent Title="Write Code" Start="-8589241828854775808" Stop="-8589241756854775808" />
<MyEvent Title="???" Start="-8589241828854775808" Stop="-8589241756854775808" />
<MyEvent Title="Profit!" Start="-8589247048854775808" Stop="-8589246976854775808" />
</MyCalendar>
c#
xml
xml-serialization
Greg
fonte
fonte
Respostas:
Sim, GetSchema () deve retornar nulo .
Para leitura e gravação, o elemento do objeto já foi gravado, portanto, você não precisa adicionar um elemento externo na gravação. Por exemplo, você pode apenas começar a ler / escrever atributos nos dois.
Para gravação :
E para ler :
Concordo que isso é um pouco incerto, mas tudo se resume a "é seu trabalho a
Read()
tag do elemento final do wrapper".fonte
Escrevi um artigo sobre o assunto com exemplos, já que a documentação do MSDN ainda não é clara e os exemplos que você pode encontrar na Web são na maioria das vezes implementados incorretamente.
Armadilhas são manipulação de localidades e elementos vazios ao lado do que Marc Gravell já mencionou.
http://www.codeproject.com/KB/XML/ImplementIXmlSerializable.aspx
fonte
Sim, a coisa toda é um campo minado, não é? A resposta de Marc Gravell praticamente cobre, mas eu gostaria de acrescentar que, em um projeto em que trabalhei, achamos bastante estranho ter que escrever manualmente o elemento XML externo. Também resultou em nomes inconsistentes de elementos XML para objetos do mesmo tipo.
Nossa solução foi definir nossa própria
IXmlSerializable
interface, derivada da do sistema, que adicionou um método chamadoWriteOuterXml()
. Como você pode imaginar, esse método simplesmente escreveria o elemento externo, depois chamaria eWriteXml()
, em seguida, escreveria o final do elemento. Obviamente, o serializador XML do sistema não chamaria esse método; portanto, só foi útil quando fizemos nossa própria serialização, para que possa ou não ser útil no seu caso. Da mesma forma, adicionamos umReadContentXml()
método que não leu o elemento externo, apenas seu conteúdo.fonte
Se você já possui uma representação XmlDocument de sua classe ou prefere a maneira XmlDocument de trabalhar com estruturas XML, uma maneira rápida e suja de implementar o IXmlSerializable é passar esse xmldoc para as várias funções.
AVISO: XmlDocument (e / ou XDocument) é uma ordem de magnitude mais lenta que xmlreader / writer, portanto, se o desempenho é um requisito absoluto, esta solução não é para você!
fonte
A implementação da interface é abordada pelas outras respostas, mas eu queria lançar meus 2 centavos para o elemento raiz.
Eu aprendi no passado a preferir colocar o elemento raiz como metadados. Isso tem alguns benefícios:
Abaixo está um exemplo de um dicionário serializável em que o elemento raiz do dicionário é definido dessa maneira:
fonte