2010-12-01 6 views
5

Wie kann ich auf XmlAttributes zugreifen, die auf Felder in einem IXmlSerializable-Objekt unter Verwendung von XmlAttributesOverrides angewendet werden?Zugriff auf XmlAttributesOverrides hinzugefügte Attribute in IXmlSerializable-Methoden

Probe IXmlSerializable Objekt:

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

Typische Aufschalten Schöpfung:

 // 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 ... 

Erstellt Ausgang:

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

Ich brauche IXmlSerializable zu verwenden, um Erbschaftsangelegenheiten von 'Somebaseclass' zu überwinden.

Das Problem ist, dass GetCustomArributes keines der Attribute zurückgibt, die der XmlAttributeOverrides Sammlung hinzugefügt werden - oder mache ich es falsch!?

Es ist auch wahrscheinlich, dass GetCustomAttributes nicht gegeben, so Attribute sollen zurückzukehren, oder dass ich nicht verwenden XmlAttributeOverrides in einer IXmlSerializable Klasse soll.

Also ... irgendwelche Ideen oder Alternativen. Danke, dass du dir die Zeit genommen hast.

+0

Gibt es einen besonderen Grund, warum Sie können nicht nur direkt zu Person-Klasse injizieren? Zum Beispiel make Methode SetOverrides (XmlAttributeOverrides overrides) auf Person-Klasse und rufen Sie direkt vor der Serialisierung auf? –

+0

@OndrejSvejdar Dies funktioniert für die Serialisierung, aber NICHT für die Deserialisierung. –

Antwort

0

Es gibt keine Möglichkeit, das zu tun.

Der Grund ist, weil XmlSerializer Serializer-Klassen generieren wird, wenn Objekte gegeben werden, die nicht IXmlSerializable sind. Diese XML-Überschreibungsattribute werden verwendet, um diese Klassen anders zu kompilieren. XML-Überschreibungsattribute gelten nicht während der Laufzeit während der Serialisierung oder Deserialisierung; Deshalb sind sie nicht zugänglich.

Klassen, die IXmlSerializable erben, generieren keine Serialisierungsklasse. Wenn Sie XML-Überschreibungsattribute verwenden möchten, müssen Sie den Serializer-Klassencompiler nicht überschreiben. Verwenden Sie diese Implementierung von Person statt und lassen Sie es die Serializer Klasse generieren für Sie die gegebenen Überschreibungen auf Basis von (auch viele, viele Male schneller laufen):

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

Sie natürlich sind auch gerne Ihre eigene Serializer Klasse Compiler schreiben , aber das ist ein bisschen mehr als das, was hier passen kann. Aber die Umsetzung sollte in etwa so aussehen:

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

Kann bieten eine eigene Implementierung von XmlWriter mit Liste von Fieldinfo zu schaffen, wo Sie Verweise auf Felder gespeichert werden serialisiert. Dann übergeben Sie es an Instanz des Zieltyps (Person in Beispiel) und serialisieren nur sie. In der Hauptmethode können Sie 2 Beispiele der Serialisierung sehen: mit Name1 und ohne Name1. Und sollte auch beachten, dass die Reflexion Leistung ist langsam, so kann nur Bool-Feld erstellen (bool DoNotSerializeName1) und wenn es wahr sein wird, dann ignoriere Name1 Serialisierung. Hoffe es wird für jemanden nützlich sein ...

Person Art und Serialisierung Beispiel:

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 Umsetzung:

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 
    } 
} 
Verwandte Themen