2009-02-09 14 views
6

Tengo una clase base que es compatible con la serialización XML y una clase derivada que implementa IXmlSerializable.C# Xml-Serializar una clase derivada utilizando IXmlSerializable

En este ejemplo, la clase base no implementar 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()); 
     } 
    } 
} 

Esto produce esta salida:

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

Sin embargo, me gustaría utilizar una clase base que hace no implementar IXmlSerializable. Esto evita el uso de base.Read/WriteXml. El resultado será:

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

¿Hay alguna forma de obtener el resultado deseado?

Respuesta

2

"Esto evita el uso de base.Read/WriteXml".

Normalmente, si la clase base implementada IXmlSerializable, puede hacer que sea un método virtual para que se use la versión concreta. Normalmente, también utilizaría la implementación explícita (en lugar de propiedades públicas), quizás con algunos métodos protected virtual para los detalles de implementación (aunque hacer un seguimiento de dónde está el lector/escritor en diferentes clases sería una pesadilla).

yo sepa, no hay manera de volver a utilizar XmlSerializer para escribir la base trozos, mientras que se agrega la deriva bits. IXmlSerializable es todo o nada.

+0

Viniendo de Java y su serialización es fácil, estoy un poco triste por escuchar esto. De hecho, hice la clase base, que por suerte tengo acceso, implementamos IXmlSerializable. Funciona, pero duele, porque estoy escribiendo código que no debería existir. – mafu

+0

A menos que a alguien se le ocurra un nuevo enfoque, esta es la respuesta oficial. – mafu

1

¿por qué no usar simplemente XmlSerializer en su función de lectura/escritura?

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

Porque tenía que ser serializado manualmente por razones que ya no puedo recordar. :) – mafu

4

Mejorando la respuesta de mtlung, ¿por qué no usa XmlSerializer? Puede ajustar su clase con el atributo para que pueda ser serializada de la manera que desee, y es bastante simple de hacer.

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

A continuación, serializar y deserializar sería bastante simple:

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

Y el XML resultante sería algo como esto:

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

Este método funciona mejor con "poco" clases, y es simple y limpio. Ni siquiera tiene que usar los atributos, están ahí para ayudarlo a personalizar la serialización.

Cuestiones relacionadas