2010-12-01 5 views
5

¿Cómo puedo acceder a XmlAttributes aplicado a campos en un objeto IXmlSerializable usando ?Acceder a atributos agregados XmlAttributesOverrides en métodos IXmlSerializable

la muestra objeto IXmlSerializable:

public class Person : SomeBaseClass, IXmlSerializable 
{ 
    public string Name1; 

    public string Name2; 

    [XmlIgnore] 
    public string Name3; 

    public Person() 
    { 
    } 

    public Person(string first, string second, string third) 
    { 
     Name1 = first; 
     Name2 = second; 
     Name3 = third; 
    } 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     // .... 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     FieldInfo[] finfo = this.GetType().GetFields(); 

     foreach (FieldInfo finf in finfo) 
     { 
      FieldAttributes attr = finf.Attributes; 
      object[] atts = finf.GetCustomAttributes(true); 

      if (atts.Length == 0) 
      { 
       // handle field with no attributes ... should be just Name1 
       // but also get Name2 since XmlAttributOverrides' XmlIgnore is not 
       // included with GetCustomAttributes results. 
       writer.WriteElementString(finf.Name, (string)finf.GetValue(this)); 
      } 
      else 
      { 
       // handle field with attributes ... should be Name2 and Name3 
       // but only get Name3 via [XmlIgnore] compiler generated attribute 
      } 
     } 
    } 
} 

típica creación de anulación:

 // parent app ... 

    public XmlSerializer CreateOverrider() 
    { 
     XmlAttributeOverrides xOver = new XmlAttributeOverrides(); 
     XmlAttributes attrs = new XmlAttributes(); 

     attrs.XmlIgnore = true; 
     xOver.Add(typeof(Person), "name2", attrs); 

     XmlSerializer xSer = new XmlSerializer(typeof(Person), xOver); 
     return xSer; 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     // Custom XmlSerialize 
     Person pson = new Person("First", "Second", "Third"); 

     XmlSerializer serializer = CreateOverrider(); 
     TextWriter writer = new StreamWriter("PersonOverride.xml"); 

     serializer.Serialize(writer, pson); 
     writer.Close(); 
    } 

    // etc ... 

Creado salida:

<?xml version="1.0" encoding="utf-8"?><Person><Name1>First</Name1><Name2>Second</Name2></Person> 

necesito utilizar IXmlSerializable para superar los problemas de herencia de 'SomeBaseClass'.

El problema es que GetCustomArributes no devuelve ninguno de los atributos agregados a la colección XmlAttributeOverrides - ¡o lo estoy haciendo incorrectamente!

También es probable que GetCustomAttributes no se SUPONE para devolver tales atributos adicionales, o que se supone que no debo usar XmlAttributeOverrides en una clase IXmlSerializable.

Entonces ... cualquier idea o alternativa. Gracias por tomarse el tiempo.

+0

¿Hay alguna razón en particular, ¿por qué no se puede simplemente les inyecta a la clase Persona directa? Por ejemplo, haga el método SetOverrides (XmlAttributeOverrides overrides) en la clase Person y llámelo antes de que se serialice. –

+0

@OndrejSvejdar Eso funcionará para la serialización pero NO para la deserialización. –

Respuesta

0

No hay forma de hacerlo.

La razón es porque XmlSerializer generará clases serializador cuando se les da objetos que no son IXmlSerializable. Esos atributos de anulación de XML se utilizarán para compilar esas clases de forma diferente. Los atributos de anulación XML no se aplican en tiempo de ejecución durante la serialización o deserialización; es por eso que no son accesibles.

Las clases que heredan IXmlSerializable no generan una clase de serializador. Si desea utilizar los atributos de anulación de XML, entonces no deberá anular el compilador de la clase de serializador. Utilizar esta implementación de Person lugar y dejar que genere la clase serializador para usted basado en las sustituciones dadas (también ejecutar muchas muchas veces más rápido):

public class Person : SomeBaseClass 
{ 
    public string Name1; 

    public string Name2; 

    [XmlIgnore] 
    public string Name3; 

    public Person() 
    { 
    } 

    public Person(string first, string second, string third) 
    { 
     Name1 = first; 
     Name2 = second; 
     Name3 = third; 
    } 
} 

Usted, por supuesto, también son bienvenidos a escribir su propio compilador clase serializador , pero eso es un poco más complicado de lo que cabe aquí. Sin embargo, la aplicación debe ser algo como esto:

public static Type GeneratePersonSerializer(XmlAttributeOverrides overrides) { 
    //here compile a class to generate a Type inheriting from IXmlSerializable 
    //the serializer logic in this class should be generated by taking into 
    //account the given XmlAttributeOverrides 
    //the type returned should be the Type passed into new XmlSerializer(Type type) 
} 
0

Puede ofrecer a crear su propia implementación de XmlWriter con la lista de FieldInfo donde se va a almacenar referencias a los campos para serializar. A continuación, páselo a instancia del tipo de destino (Persona en el ejemplo) y serialícelos solo. En el método principal, puede ver 2 ejemplos de serialización: con Nombre1 y sin Nombre1. Y también debe tener en cuenta que el rendimiento de la reflexión es lento, por lo que puede ser solo crear el campo bool (bool DoNotSerializeName1) y, si es cierto, ignorar la serialización de Name1. Espero que sea útil para alguien ...

tipo de persona y el ejemplo de serialización: aplicación

using System; 
using System.IO; 
using System.Linq; 
using System.Reflection; 
using System.Text; 
using System.Xml; 
using System.Xml.Schema; 
using System.Xml.Serialization; 

namespace XmlCustomSerializer 
{ 
    public class Person : IXmlSerializable 
    { 
     public string Name1; 

     public string Name2; 

     [XmlIgnore] 
     public string Name3; 

     public Person() 
     { 
     } 

     public Person(string first, string second, string third) 
     { 
      Name1 = first; 
      Name2 = second; 
      Name3 = third; 
     } 

     public XmlSchema GetSchema() 
     { 
      return null; 
     } 

     public void ReadXml(XmlReader reader) 
     { 
      // .... 
     } 

     private static FieldInfo[] _cachedFields = null; 
     public void WriteXml(XmlWriter writer) 
     { 
      var customWriter = writer as XmlCustomWriter; 
      if (customWriter == null) 
       throw new ArgumentException("writer"); 

      if (_cachedFields == null) 
      { 
       _cachedFields = typeof(Person).GetFields(); 
      } 

      foreach (FieldInfo finf in customWriter.FieldsToSerialize) 
      { 
       if (_cachedFields.Contains(finf)) 
       { 
        writer.WriteElementString(finf.Name, (string)finf.GetValue(this)); 
       } 
      } 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var person = new Person 
      { 
       Name1 = "Some", 
       Name2 = "Person", 
       Name3 = "Name" 
      }; 

      var settings = new XmlWriterSettings { Indent = true, Encoding = Encoding.ASCII }; 
      var allFields = typeof(Person).GetFields(); 

      XmlSerializer xSer = new XmlSerializer(typeof(Person)); 

      using (var stream = new MemoryStream()) 
      { 
       var xmlCustomWriter = new XmlCustomWriter(
        XmlWriter.Create(new StreamWriter(stream), settings)); 

       //serialize all fields 
       xmlCustomWriter.FieldsToSerialize = allFields; 

       xSer.Serialize(xmlCustomWriter, person); 

       stream.Seek(0, SeekOrigin.Begin); 
       Console.WriteLine(new StreamReader(stream).ReadToEnd()); 
      } 

      using (var stream = new MemoryStream()) 
      { 
       var xmlCustomWriter = new XmlCustomWriter(
        XmlWriter.Create(new StreamWriter(stream), settings)); 

       //serialize 2 fields 
       xmlCustomWriter.FieldsToSerialize = allFields.Skip(1); 

       xSer.Serialize(xmlCustomWriter, person); 

       stream.Seek(0, SeekOrigin.Begin); 
       Console.WriteLine(new StreamReader(stream).ReadToEnd()); 
      } 

      Console.Read(); 
     } 
    } 
} 

XmlCustomWriter:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reflection; 
using System.Xml; 

namespace XmlCustomSerializer 
{ 
    public class XmlCustomWriter : XmlWriter 
    { 
     private readonly XmlWriter _innerWriter; 

     public XmlCustomWriter(XmlWriter innerWriter) 
     { 
      if (innerWriter == null) 
       throw new ArgumentNullException("innerWriter"); 
      _innerWriter = innerWriter; 
      FieldsToSerialize = Enumerable.Empty<FieldInfo>(); 
     } 

     public IEnumerable<FieldInfo> FieldsToSerialize { get; set; } 

     #region Implement XmlWriter 
     public override void Flush() 
     { 
      _innerWriter.Flush(); 
     } 

     public override string LookupPrefix(string ns) 
     { 
      return _innerWriter.LookupPrefix(ns); 
     } 

     public override void WriteBase64(byte[] buffer, int index, int count) 
     { 
      _innerWriter.WriteBase64(buffer, index, count); 
     } 

     public override void WriteCData(string text) 
     { 
      _innerWriter.WriteCData(text); 
     } 

     public override void WriteCharEntity(char ch) 
     { 
      _innerWriter.WriteCharEntity(ch); 
     } 

     public override void WriteChars(char[] buffer, int index, int count) 
     { 
      _innerWriter.WriteChars(buffer, index, count); 
     } 

     public override void WriteComment(string text) 
     { 
      _innerWriter.WriteComment(text); 
     } 

     public override void WriteDocType(string name, string pubid, string sysid, string subset) 
     { 
      _innerWriter.WriteDocType(name, pubid, sysid, subset); 
     } 

     public override void WriteEndAttribute() 
     { 
      _innerWriter.WriteEndAttribute(); 
     } 

     public override void WriteEndDocument() 
     { 
      _innerWriter.WriteEndDocument(); 
     } 

     public override void WriteEndElement() 
     { 
      _innerWriter.WriteEndElement(); 
     } 

     public override void WriteEntityRef(string name) 
     { 
      _innerWriter.WriteEntityRef(name); 
     } 

     public override void WriteFullEndElement() 
     { 
      _innerWriter.WriteFullEndElement(); 
     } 

     public override void WriteProcessingInstruction(string name, string text) 
     { 
      _innerWriter.WriteProcessingInstruction(name, text); 
     } 

     public override void WriteRaw(string data) 
     { 
      _innerWriter.WriteRaw(data); 
     } 

     public override void WriteRaw(char[] buffer, int index, int count) 
     { 
      _innerWriter.WriteRaw(buffer, index, count); 
     } 

     public override void WriteStartAttribute(string prefix, string localName, string ns) 
     { 
      _innerWriter.WriteStartAttribute(prefix, localName, ns); 
     } 

     public override void WriteStartDocument(bool standalone) 
     { 
      _innerWriter.WriteStartDocument(standalone); 
     } 

     public override void WriteStartDocument() 
     { 
      _innerWriter.WriteStartDocument(); 
     } 

     public override void WriteStartElement(string prefix, string localName, string ns) 
     { 
      _innerWriter.WriteStartElement(prefix, localName, ns); 
     } 

     public override WriteState WriteState 
     { 
      get { return _innerWriter.WriteState; } 
     } 

     public override void WriteString(string text) 
     { 
      _innerWriter.WriteString(text); 
     } 

     public override void WriteSurrogateCharEntity(char lowChar, char highChar) 
     { 
      _innerWriter.WriteSurrogateCharEntity(lowChar, highChar); 
     } 

     public override void WriteWhitespace(string ws) 
     { 
      _innerWriter.WriteWhitespace(ws); 
     } 
     #endregion Implement XmlWriter 
    } 
} 
Cuestiones relacionadas