Как только программист решит реализовать IXmlSerializable
, каковы правила и лучшие практики для его реализации? Я слышал, что GetSchema()
должен вернуться null
и ReadXml
должен перейти к следующему элементу, прежде чем вернуться. Это правда? А как насчет WriteXml
- должен ли он написать корневой элемент для объекта или предполагается, что корень уже записан? Как должны обрабатываться и записываться дочерние объекты?
Вот образец того, что у меня сейчас. Я обновлю его, когда получу хорошие ответы.
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
<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
источник
источник
Ответы:
Да, GetSchema () должна возвращать ноль .
Как для чтения, так и для записи, элемент объекта уже записан, поэтому вам не нужно добавлять внешний элемент в записи. Например, вы можете просто начать чтение / запись атрибутов в двух.
Для записи :
И для чтения :
Я согласен, что это немного неясно, но все сводится к тому, что «это ваша работа с
Read()
тегом конечного элемента оболочки».источник
Я написал одну статью на эту тему с примерами, поскольку документация MSDN к настоящему моменту довольно неясна, а примеры, которые вы можете найти в Интернете, в большинстве случаев неверно реализованы.
Подводные камни - это управление локалями и пустыми элементами, помимо того, что уже упоминал Марк Гравелл.
http://www.codeproject.com/KB/XML/ImplementIXmlSerializable.aspx
источник
Да, все это немного минное поле, не так ли? Ответ Марка Гравелла в значительной степени охватывает его, но я хотел бы добавить, что в проекте, над которым я работал, нам было довольно неудобно вручную писать внешний элемент XML. Это также привело к несовместимым именам элементов XML для объектов одного типа.
Наше решение состояло в том, чтобы определить наш собственный
IXmlSerializable
интерфейс, производный от системного, в который был добавлен вызываемый методWriteOuterXml()
. Как вы можете догадаться, этот метод просто записывает внешний элемент, затем вызываетWriteXml()
, а затем записывает конец элемента. Конечно, системный XML-сериализатор не будет вызывать этот метод, поэтому он был полезен только тогда, когда мы выполнили собственную сериализацию, так что это может или не может быть полезным в вашем случае. Точно так же мы добавилиReadContentXml()
метод, который не считывал внешний элемент, а только его содержимое.источник
Если у вас уже есть представление XmlDocument вашего класса или вы предпочитаете способ работы с XML-структурами XmlDocument, быстрый и грязный способ реализации IXmlSerializable - просто передать этот xmldoc различным функциям.
ВНИМАНИЕ: XmlDocument (и / или XDocument) на порядок медленнее, чем xmlreader / writer, поэтому, если производительность является абсолютным требованием, это решение не для вас!
источник
Реализация интерфейса покрыта другими ответами, но я хотел добавить 2 цента для корневого элемента.
В прошлом я научился отдавать корневой элемент метаданным. Это имеет несколько преимуществ:
Ниже приведен пример сериализуемого словаря, в котором корневой элемент словаря определен следующим образом:
источник