2009-02-09 3 views
6

У меня есть базовый класс, который совместим с сериализацией XML и производным классом, который реализует IXmlSerializable.C# 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 /> 

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

ответ

2

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

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

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

+0

Исходя из Java, и это мертвая простая сериализация, мне немного грустно слышать это. Я фактически сделал базовый класс, к которому я, к счастью, имею доступ, реализую IXmlSerializable. Он работает, но это как-то больно, потому что я пишу код, который не должен существовать. – mafu

+0

Если кто-то не придумает новый подход, это официальный ответ. – mafu

1

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

XmlSerializer s = new XmlSerializer(typeof(Foo)); 
s.Serialize(writer, base); 
+1

Потому что его пришлось вручную сериализовать по причинам, которые я больше не могу вспомнить. :) – mafu

4

Улучшение ответа 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" классы, и это просто и чисто. Вам даже не нужно использовать атрибуты, они есть, чтобы помочь вам настроить сериализацию.

Смежные вопросы