IXmlSerializable
Welche Regeln und Best Practices gibt ein Programmierer , wenn er sich für die Implementierung entscheidet? Ich habe gehört, dass dies GetSchema()
zurückkehren null
und ReadXml
vor der Rückkehr zum nächsten Element wechseln sollte. Ist das wahr? Und was ist mit WriteXml
- sollte es ein Wurzelelement für das Objekt schreiben oder wird angenommen, dass die Wurzel bereits geschrieben ist? Wie sollen untergeordnete Objekte behandelt und geschrieben werden?
Hier ist ein Beispiel von dem, was ich jetzt habe. Ich werde es aktualisieren, sobald ich gute Antworten bekomme.
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());
}
}
Entsprechendes Beispiel-XML
<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
quelle
quelle
Antworten:
Ja, GetSchema () sollte null zurückgeben .
Sowohl beim Lesen als auch beim Schreiben wurde das Objektelement bereits geschrieben, sodass Sie beim Schreiben kein äußeres Element hinzufügen müssen. Zum Beispiel können Sie einfach mit dem Lesen / Schreiben von Attributen in beiden beginnen.
Zum Schreiben :
Und zum Lesen :
Ich bin damit einverstanden, dass dies ein wenig unklar ist, aber es läuft darauf hinaus, "es ist Ihre Aufgabe,
Read()
das Endelement-Tag des Wrappers zu erstellen".quelle
Ich habe einen Artikel zu diesem Thema mit Beispielen geschrieben, da die MSDN-Dokumentation inzwischen ziemlich unklar ist und die Beispiele, die Sie im Internet finden, die meiste Zeit falsch implementiert sind.
Fallstricke sind der Umgang mit Gebietsschemas und leeren Elementen neben dem, was Marc Gravell bereits erwähnt hat.
http://www.codeproject.com/KB/XML/ImplementIXmlSerializable.aspx
quelle
Ja, das Ganze ist ein bisschen wie ein Minenfeld, nicht wahr? Marc Gravells Antwort deckt es ziemlich genau ab, aber ich möchte hinzufügen, dass es in einem Projekt, an dem ich gearbeitet habe, ziemlich umständlich war, das äußere XML-Element manuell schreiben zu müssen. Dies führte auch zu inkonsistenten XML-Elementnamen für Objekte desselben Typs.
Unsere Lösung bestand darin, eine eigene
IXmlSerializable
Schnittstelle zu definieren , die vom System abgeleitet wurde und eine Methode namens hinzufügteWriteOuterXml()
. Wie Sie sich vorstellen können, würde diese Methode einfach das äußere Element schreiben, dann aufrufenWriteXml()
und dann das Ende des Elements schreiben. Natürlich würde der System-XML-Serializer diese Methode nicht aufrufen, daher war sie nur nützlich, wenn wir unsere eigene Serialisierung durchgeführt haben, sodass dies in Ihrem Fall möglicherweise hilfreich ist oder nicht. In ähnlicher Weise haben wir eineReadContentXml()
Methode hinzugefügt , die nicht das äußere Element, sondern nur dessen Inhalt gelesen hat.quelle
Wenn Sie bereits eine XmlDocument-Darstellung Ihrer Klasse haben oder die XmlDocument-Methode zum Arbeiten mit XML-Strukturen bevorzugen, können Sie IXmlSerializable schnell und unkompliziert implementieren, indem Sie dieses xmldoc einfach an die verschiedenen Funktionen übergeben.
WARNUNG: XmlDocument (und / oder XDocument) ist um eine Größenordnung langsamer als xmlreader / writer. Wenn also Leistung unbedingt erforderlich ist, ist diese Lösung nichts für Sie!
quelle
Die Schnittstellenimplementierung wird durch die anderen Antworten abgedeckt, aber ich wollte meine 2 Cent für das Stammelement einwerfen.
Ich habe in der Vergangenheit gelernt, das Stammelement lieber als Metadaten zu verwenden. Dies hat einige Vorteile:
Unten finden Sie ein Beispiel für ein serialisierbares Wörterbuch, in dem das Wörterbuchstammelement auf diese Weise definiert ist:
quelle