2010-12-01 2 views
5

을 사용하여 IXmlSerializable 개체의 필드에 적용된 XmlAttributes에 어떻게 액세스합니까?XmlAttributesOverrides에서 IXmlSerializable 메서드의 특성을 추가했습니다.

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

일반 재정의 생성 :

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

만든 출력 :

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

내가 'SomeBaseClass'에서 상속 문제를 극복하기 위해 IXmlSerializable를 사용해야합니다.

문제는 GetCustomArributes이 (가) XmlAttributeOverrides 컬렉션에 추가 된 속성을 반환하지 않거나 잘못하고 있다는 것입니다.

GetCustomAttributes이 추가 된 특성을 반환하지 않거나 클래스에서 XmlAttributeOverrides을 사용하지 않아도되는 것 같습니다.

그래서 ... 아이디어 나 대안. 시간을내어 주셔서 감사합니다.

+0

어떤 특별한 이유가 그냥 직접 Person 클래스에 주입 할 수없는 이유 있나요? 예를 들어, Person 클래스에서 SetOverrides (XmlAttributeOverrides 오버라이드) 메소드를 만들고 직렬화되기 전에 바로 호출 할 수 있습니까? –

+0

@OndrejSvejdar 직렬화에는 작동하지만 비 직렬화에는 작동하지 않습니다. –

답변

0

그렇게 할 방법이 없습니다.

이유는 이 아닌 지정된 개체가있을 때 XmlSerializer이 serializer 클래스를 생성하기 때문입니다. 이러한 XML Overrides Attributes는 해당 클래스를 다르게 컴파일하는 데 사용됩니다. XML은 속성을 재정의합니다. 은 직렬화 또는 직렬화 해제 중에 런타임에 적용되지 않습니다.; 그것이 접근 할 수없는 이유입니다.

IXmlSerializable을 상속받은 클래스는 serializer 클래스를 생성하지 않습니다. XML Override Attributes를 사용하려면 serializer 클래스 컴파일러를 재정의하지 않아야합니다. 대신 Person의 구현을 사용하고 주어진 재정을 기반 것이 시리얼 라이저 클래스를 생성 할 수 있습니다 (또한 빠르게 많은 여러 번 실행됩니다) :

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

당신은 물론 또한 자신의 시리얼 클래스 컴파일러를 쓰기에 오신 것을 환영합니다 그러나 그것은 여기에 적합 할 수있는 것보다 조금 더 복잡합니다. 하지만 구현은 다음과 비슷한 모습이 될 것

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

당신이 직렬화 필드에 대한 참조를 저장하는 곳의 fieldInfo의 목록 XmlWriter를 당신 자신의 구현을 만들기 위해 제공 할 수 있습니다. 그런 다음 대상 유형의 인스턴스 (예 : 사람)로 전달하고 해당 항목 만 직렬화하십시오. main 메소드에서 직렬화의 두 가지 예제를 볼 수 있습니다 : Name1과 Name1. 또한 반사 성능이 느린 것을 알아야합니다. bool 필드 (bool DoNotSerializeName1)를 만들면 true 일 경우 Name1 serialization을 무시하십시오. 희망은 누군가에게 유용 할 것입니다 ...

사람 유형 및 직렬화 예 :

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 
    } 
} 
관련 문제