C # Xml-сериализация производного класса с использованием IXmlSerializable - PullRequest
7 голосов
/ 09 февраля 2009

У меня есть базовый класс, совместимый с сериализацией XML, и производный класс, который реализует IXmlSerializable.

В этом примере базовый класс реализует IXmlSerializable:


using System.Diagnostics;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace XmlSerializationDerived
{
    public class Foo
    {
        public int fooProp;

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            fooProp = int.Parse (reader.ReadElementString ("fooProp"));
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString ("fooProp", fooProp.ToString ());
        }
    }

    public class Bar : Foo, IXmlSerializable
    {
        public new void ReadXml(XmlReader reader)
        {
            base.ReadXml (reader);
        }

        public new void WriteXml(XmlWriter writer)
        {
            base.WriteXml (writer);
        }

        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder ();
            XmlWriter writer = XmlWriter.Create (sb);

            Bar bar = new Bar ();
            bar.fooProp = 42;

            XmlSerializer serializer = new XmlSerializer (typeof (Bar));
            serializer.Serialize (writer, bar);

            Debug.WriteLine (sb.ToString ());
        }
    }
}

Это дает такой вывод:

<?xml version="1.0" encoding="utf-16"?><Bar><fooProp>42</fooProp></Bar>

Однако я хотел бы использовать базовый класс, который не реализует IXmlSerializable. Это предотвращает использование base.Read/WriteXml. Результат будет:

<?xml version="1.0" encoding="utf-16"?><Bar />

Есть ли еще способ получить желаемый результат?

Ответы [ 3 ]

4 голосов
/ 22 мая 2009

Улучшение ответа mtlung, почему вы не используете XmlSerializer? Вы можете настроить свой класс с помощью атрибута, чтобы его можно было сериализовать так, как вы хотите, и это довольно просто сделать.

using System.Xml.Serialization;

...

[XmlRoot("someclass")]
public class SomeClass
{
    [XmlAttribute("p01")]
    public int MyProperty01
    {
        get { ... }
    }

    [XmlArray("sometypes")]
    public SomeType[] MyProperty02
    {
        get { ... }
    }

    [XmlText]
    public int MyProperty03
    {
        get { ... }
    }

    public SomeClass()
    {
    }
}

Тогда сериализовать и десериализовать было бы довольно просто:

void Save(SomeClass obj)
{
    XmlSerializer xs = new XmlSerializer(typeof(SomeClass));
    using (FileStream fs = new FileStream("c:\\test.xml", ...))
    {
        xs.Serialize(fs, obj);
    }
}

void Load(out SomeClass obj)
{
    XmlSerializer xs = new XmlSerializer(typeof(SomeClass));
    using (FileStream fs = new FileStream("c:\\test.xml", ...))
    {
        obj = xs.Deserialize(fs);
    }
}

И полученный XML будет выглядеть примерно так:

<someclass p01="...">
  <sometype>
    <!-- SomeType serialized objects as child elements -->
  </sometype>
  # value of "MyProperty03" as text #
</someclass>

Этот метод лучше работает с классами "POCO", и он прост и чист. Вам даже не нужно использовать атрибуты, они есть, чтобы помочь вам настроить сериализацию.

2 голосов
/ 09 февраля 2009

"Это предотвращает использование base.Read/WriteXml."

Как правило, если в базовом классе реализован IXmlSerializable, вы можете сделать его методом virtual, чтобы использовать конкретную версию. Как правило, вы также используете явную реализацию (а не публичные свойства) - возможно, с некоторыми protected virtual методами для деталей реализации (хотя отслеживание того, где читатель / писатель находится в разных классах, было бы кошмаром).

AFAIK, нет способа повторно использовать XmlSerializer для записи base битов, в то время как вы добавляете производные биты. IXmlSerializable - это все или ничего.

1 голос
/ 15 мая 2009

почему бы просто не использовать XmlSerializer в вашей функции чтения / записи?

XmlSerializer s = new XmlSerializer(typeof(Foo));
s.Serialize(writer, base);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...