2011-01-18 2 views
2

우리 프로젝트에서는 XmlSerializer를 광범위하게 사용합니다. 우연히 매개 변수없는 생성자가없는 클래스를 찾았습니다. 직렬화 프로세스를 중단해야한다고 생각했지만 그렇지 않았습니다. 이 문제를 조사하여XmlSerializer 및 IEnumerable : 매개 변수없는 생성자없이 직렬화 가능 : 버그?

내가 XmlSerializer를이IEnumerable을 역 직렬화/직렬화 할 때 이상한 동작하는지, 발견 다음 열거의

  • 모든 요소를 ​​직렬화
  • 클래스는 구현하기 위해 필요 추가 (개체) 메서드
  • 이 클래스에있을 수있는 다른 모든 속성을 무시합니다.
  • 이 속성을 사용하여 getter를 호출하고 반환 된 인스턴스를 serialization에 다시 사용합니다 (XmlSerializer가 매개 변수없는 생성자없이 작동 할 수 있음).

다음 예를 살펴보십시오. 삽입 부분은 ODD1, ODD2입니다. good5와 good6은 내가 사실 일 것으로 예상했을 때 거짓입니다.

이 동작에 대한 이유가 있습니까?

IXmlSerializable을 손으로 구현할 때 XmlSerializer가 deserialization을 위해 속성에서 반환 한 인스턴스를 다시 사용하도록 할 수 있습니까?

using System.Collections; 
using System.Collections.Generic; 
using System.IO;  
using System.Xml; 
using System.Xml.Schema; 
using System.Xml.Serialization; 

namespace Test 
{ 
    public static class Program 
    { 
     public static void Main() 
     { 
      HostingClass host = new HostingClass(); 

      host.AutomaticSerialization.StringProperty = "AUTO"; 
      host.SelfImplementedSerialization.StringProperty = "SELF"; 

      bool good1 = host.AutomaticSerialization.FromConstructor == "PARAMETER"; 
      bool good2 = host.SelfImplementedSerialization.FromConstructor == "PARAMETER"; 
      bool good3 = host.AutomaticSerialization.StringProperty == "AUTO"; 
      bool good4 = host.SelfImplementedSerialization.StringProperty == "SELF"; 

      XmlSerializer serializer = new XmlSerializer(typeof(HostingClass)); 

      using (StringWriter sw = new StringWriter()) 
      { 
       serializer.Serialize(sw, host); 

       using (StringReader sr = new StringReader(sw.ToString())) 
       { 
        host = (HostingClass)serializer.Deserialize(sr); 
       } 
      } 

      bool good5 = host.AutomaticSerialization.FromConstructor == null; //is false 
      bool good6 = host.AutomaticSerialization.StringProperty == "AUTO"; //is false 

      bool good7 = host.SelfImplementedSerialization.FromConstructor == null; 
      bool good8 = host.SelfImplementedSerialization.StringProperty == "SELF"; 

     } 
    } 

    public class HostingClass 
    { 
     private SelfImplementedSerialization _selfImplementedSerialization; 
     public SelfImplementedSerialization SelfImplementedSerialization 
     { 
      get 
      { 
       return _selfImplementedSerialization 
         ?? (_selfImplementedSerialization = new SelfImplementedSerialization("PARAMETER")); 
      } 
      set { _selfImplementedSerialization = value; } 
     } 

     private AutomaticSerialization _automaticSerialization; 
     public AutomaticSerialization AutomaticSerialization 
     { 
      get 
      { 
       return _automaticSerialization 
         ?? (_automaticSerialization = new AutomaticSerialization("PARAMETER")); //the returned object is used while deserializing 
      } 
      set { _automaticSerialization = value; } 
     } 
    } 

    public class SelfImplementedSerialization : IXmlSerializable, IEnumerable<int> 
    { 
     public SelfImplementedSerialization() { } 
     public SelfImplementedSerialization(string parameter) 
     { 
      FromConstructor = parameter; 
     } 

     public string StringProperty { get; set; } 
     [XmlIgnore] 
     public string FromConstructor { get; set; } 

     public void ReadXml(XmlReader reader) 
     { 
      reader.ReadStartElement(); 
      StringProperty = reader.ReadElementString("StringProperty"); 
      reader.ReadEndElement(); 
     } 

     public void WriteXml(XmlWriter writer) 
     { 
      writer.WriteElementString("StringProperty", StringProperty); 
     } 

     public IEnumerator<int> GetEnumerator() 
     { 
      yield return 1; 
      yield return 2; 
     } 

     IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 
     public XmlSchema GetSchema() { return null; } 
    } 


    public class AutomaticSerialization : IEnumerable<int> 
    { 
     //ODD1: Serialization possible w/o public parameterless constructor 
     //public AutomaticSerialization() {} 
     public AutomaticSerialization(string parameter) 
     { 
      FromConstructor = parameter; 
     } 

     //ODD2: Element not serialized, only the IEnumerable Interface is serialized 
     [XmlElement("SP")] 
     public string StringProperty { get; set; } 
     [XmlIgnore] 
     public string FromConstructor { get; set; } 

     public IEnumerator<int> GetEnumerator() 
     { 
      yield return 1; 
      yield return 2; 
     } 

     public void Add(object o) 
     { 
      //requirement of XmlSerializer when serializing IEnumerables 
     } 

     IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 
    } 
} 

답변

4

동작의 이유는 이것이 항상 효과가 있었던 때문입니다. XmlSerializer class에서

:

XmlSerializerIEnumerable 또는 ICollection를 구현하는 클래스에 특별한 치료를 제공합니다. IEnumerable을 구현하는 클래스 은 이 단일 매개 변수를 사용하는 public Add 메서드를 구현해야합니다. GetEnumerator 또는 유형의 기지 하나로부터 반환 된 값에 Current 속성으로부터 리턴 된 바와 같이 추가 메소드의 파라미터 동일한 유형이어야. IEnumerable 외에 ICollection (예 : CollectionBase) 를 구현하는 클래스는 정수를 취하는 공개 항목 인덱스 속성 (C#에서 인덱서 )가 있어야합니다, 그것은 정수 유형의 공개 Count 속성이 있어야합니다. 메서드에 대한 매개 변수는 이 Item 속성에서 반환 된 것과 동일한 형식이거나 형식이어야합니다. 이 ICollection 인 경우 GetEnumerator을 호출하지 않고 의 값을 인덱싱 된 Item 속성에서 검색합니다.

+0

안녕하세요 John, 답변 해 주셔서 감사합니다.어떤 경우에는 getter가 먼저 호출되고 반환 된 객체는 deserialization에 사용되며, 다른 경우에는 setter가 먼저 scatch에서 deserialize 된 객체와 함께 호출됩니다. 그건 나에게별로 의미가 없다. – mklein

+2

@mklein : sense와 XML Serializer는 실제로 섞이지 않습니다. 이 "소시지"가 어떻게 만들어 졌는지 알기를 원한다면 소스 코드를 살펴 보는 것이 좋습니다. –

+0

Re : "동작의 이유는 이것이 항상 효과가 있었던 것입니다." 같은 소리 : - 왜 당신은 항상 사과를 먹고 있습니까? - 내가 사과를 먹는 이유는 내가 항상 그들을 먹고 있었기 때문이다. – Vova

관련 문제