2009-02-09 11 views
6

Ho una classe base che è compatibile con la serializzazione XML e una classe derivata che implementa IXmlSerializable.C# Xml-Serializzazione di una classe derivata utilizzando IXmlSerializable

In questo esempio, la classe di base attui 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()); 
     } 
    } 
} 

Questo produce questo output:

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

Tuttavia, vorrei usare una classe base che fa non implementare IXmlSerializable. Ciò impedisce l'utilizzo di base.Read/WriteXml. Il risultato sarà:

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

C'è un modo per ottenere ancora il risultato desiderato?

risposta

2

"Ciò impedisce l'utilizzo di base.Read/WriteXml."

In genere, se la classe base è implementata IXmlSerializable, è possibile renderlo un metodo virtual in modo che venga utilizzata la versione concreta. In genere, si utilizzano anche l'implementazione esplicita (piuttosto che le proprietà pubbliche), forse con alcuni metodi protected virtual per i dettagli dell'implementazione (sebbene tenere traccia di dove il lettore/scrittore si trova in diverse classi sarebbe un incubo).

per quanto ne so, non c'è modo di ri-uso XmlSerializer di scrivere alla base bit, mentre si aggiunge il derivato bit. IXmlSerializable è tutto-o-niente.

+0

Provenendo da Java ed è una serializzazione facile, sono un po 'triste sentirlo. Ho effettivamente realizzato la classe base, che per fortuna ho accesso, implementare IXmlSerializable. Funziona, ma mi fa male, perché sto scrivendo un codice che non dovrebbe esistere. – mafu

+0

A meno che qualcuno non presenti un nuovo approccio, questa è la risposta ufficiale. – mafu

1

perché non utilizzare semplicemente XmlSerializer nella funzione di lettura/scrittura?

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

Perché doveva essere serializzato manualmente per motivi che non ricordo più. :) – mafu

4

Migliorare la risposta di mtlung, perché non usi XmlSerializer? Puoi accordare la tua classe con l'attributo in modo che possa essere serializzato nel modo desiderato, ed è piuttosto semplice da fare.

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() 
    { 
    } 
} 

Poi, serializzazione e deserializzazione sarebbe piuttosto semplice:

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); 
    } 
} 

E l'XML risultante sarebbe qualcosa di simile:

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

Questo metodo funziona meglio con "POCO" classi, ed è semplice e pulito. Non è nemmeno necessario utilizzare gli attributi, sono lì per aiutarti a personalizzare la serializzazione.