2012-07-19 2 views
2

는 코드와 클래스 다음 사항을 고려 :올바른 직렬화하지만 잘못된 직렬화는

<?xml version="1.0" encoding="utf-8"?> 
<Elements xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <element1 Order="1"> 
    <name1>Name1</name1> 
    <collection> 
     <Foo1> 
     <FooName>FooName1</FooName> 
     <deff1>10</deff1> 
     </Foo1> 
     <Foo2> 
     <FooName>FooName2</FooName> 
     <deff2>true</deff2> 
     </Foo2> 
    </collection> 
    </element1> 
    <element2 Order="2"> 
    <name2>Name2</name2> 
    </element2> 
</Elements> 

하지만 올바르게 역 직렬화 할 수 없습니다 내가 그것을 실행할 때

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

namespace ConsoleApplication1 
{ 

    public class Element1 
    { 
     [XmlAttribute] 
     public int Order { get; set; } 
     public string name1 { get; set; } 
     public ElementCollcetion collection { get; set; } 
    } 

    public class Element2 
    { 
     [XmlAttribute] 
     public int Order { get; set; } 
     public string name2 { get; set; } 
    } 

    public class Elements 
    { 
     public Element1 element1 { get; set; } 
     public Element2 element2 { get; set; } 
    } 

    public interface IFoo 
    { 
     string FooName { get; set; } 
    } 

    public class Foo1 : IFoo 
    { 
     public string FooName { get; set; } 
     public int deff1 { get; set; } 
    } 

    public class Foo2 : IFoo 
    { 
     public string FooName { get; set; } 
     public bool deff2 { get; set; } 
    } 

    public class ElementCollcetion : List<IFoo>, IXmlSerializable 
    { 
     public System.Xml.Schema.XmlSchema GetSchema() 
     { 
      return null; 
     } 

     public void ReadXml(System.Xml.XmlReader reader) 
     { 
      XmlSerializer serializer = null; 
      bool flag; 

      reader.Read(); 
      while (true) 
      { 
       flag = false; 

       if (string.Compare(reader.Name, typeof(Foo1).Name) == 0) 
       { 
        serializer = new XmlSerializer(typeof(Foo1)); 
        flag = true; 
       } 
       else if (string.Compare(reader.Name, typeof(Foo2).Name) == 0) 
       { 
        serializer = new XmlSerializer(typeof(Foo2)); 
        flag = true; 
       } 

       if (flag) 
        this.Add((IFoo)serializer.Deserialize(reader)); 
       else 
        break; 
      } 
     } 

     public void WriteXml(System.Xml.XmlWriter writer) 
     { 
      foreach (IFoo foo in this.AsEnumerable()) 
      { 
       XmlSerializer serializer = new XmlSerializer(foo.GetType()); 
       serializer.Serialize(writer, foo); 
      } 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Elements elements = new Elements() 
      { 
       element1 = new Element1 
       { 
        name1 = "Name1", 
        Order = 1, 
        collection = new ElementCollcetion(){ 
         new Foo1{deff1=10,FooName="FooName1"}, 
         new Foo2{deff2=true,FooName="FooName2"} 
        }, 
       }, 

       element2 = new Element2 
       { 
        name2 = "Name2", 
        Order = 2 
       } 
      }; 

      XmlSerializer serializer = new XmlSerializer(typeof(Elements)); 
      TextWriter textWriter = new StreamWriter(@"d:\ser.xml"); 
      serializer.Serialize(textWriter, elements); 
      textWriter.Close(); 

      TextReader textReader = new StreamReader(@"d:\ser.xml"); 
      Elements element = (Elements)serializer.Deserialize(textReader); 
      textReader.Close(); 
     } 
    } 
} 

는 XML은과 같이 ser.xml으로 생성됩니다

<?xml version="1.0" encoding="utf-8"?> 
<Elements xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <element2 Order="2"> 
    <name2>Name2</name2> 
    </element2> 
    <element1 Order="1"> 
    <name1>Name1</name1> 
    <collection> 
     <Foo1> 
     <FooName>FooName1</FooName> 
     <deff1>10</deff1> 
     </Foo1> 
     <Foo2> 
     <FooName>FooName2</FooName> 
     <deff2>true</deff2> 
     </Foo2> 
    </collection> 
    </element1> 
</Elements> 

참고을 그 : 내가 너무 같은 XML의 요소 순서를 변경하지 않는 한 파일및 serializer.UnknownElement은 두 실행 중에 발생하지 않습니다.
무엇이 문제입니까? 어떻게 해결할 수 있습니까?

--------------- 편집 ----------------------
문제가 있음을 알고 있습니다. IXmlSerializable.ReadXml() 구현. 어떤 종류의 문제와 어떻게 치료해야합니까?

답변

2

:

여기
reader.ReadEndElement(); 

또한 패턴을 사용하여 구현 한 것입니다 :와

bool isEmpty = reader.IsEmptyElement; 

reader.ReadStartElement(); //Start reading the element 
if (isEmpty) //Return on empty element 
{ 
    return; 
} 

마무리 :

일반적되는 ReadXml 구현을위한 올바른 패턴으로 시작하는 것입니다 기본적으로 독자는 하위 트리의 끝까지 올바르게 진행하지 않습니다. ReadXml 끝 부분에 reader.Read();을 추가하면 수정되지만 약간 엉망입니다. ReadSubtree()이 더 안전 할 수 있습니다. 정확하고 견고IXmlSerializable을 구현 솔직히

는 어렵다. 나는 항상 그것을 반대한다.

+0

나는'IXmlSerializable.ReadXml()'메소드 구현의 하단에 간단한'reader.Read();를 추가해야한다. – Rzassar

1

IXmlSerializable 구현을 봐야하지만 내 ReadXml 구현은 처리 순서가 역순입니다 (예 : element1 대신 element2를 먼저 찾습니다). 그렇지 않은 경우 IXmlSerializable 구현을 게시하십시오. 마크는 지적

편집

, 다른 읽기를 추가해야합니다. 문제는 reader.Read()를 호출하여 XmlReader가 컬렉션 태그 컬렉션 태그를 처리했지만 메서드 끝에 /collection, 즉 다른 reader.Read() 호출을 처리하지 못했습니다. 이것은 기본적으로 deserialization이 올바르게 진행되는 것을 막았습니다.

public void ReadXml(System.Xml.XmlReader reader) 
{ 
    XmlSerializer serializer = null; 
    bool flag; 

    bool isEmpty = reader.IsEmptyElement; 

    reader.ReadStartElement(); 
    if (isEmpty) 
    { 
     return; 
    } 

    while (true) 
    { 
     flag = false; 

     if (string.Compare(reader.Name, typeof(Foo1).Name) == 0) 
     { 
      serializer = new XmlSerializer(typeof(Foo1)); 
      flag = true; 
     } 
     else if (string.Compare(reader.Name, typeof(Foo2).Name) == 0) 
     { 
      serializer = new XmlSerializer(typeof(Foo2)); 
      flag = true; 
     } 

     if (flag) 
      this.Add((IFoo)serializer.Deserialize(reader)); 
     else 
      break; 
    } 

    reader.ReadEndElement(); 
} 
+0

ReadXml이 표시됩니다. –

+0

@Rok 이미 콘솔 애플리케이션을 실행하는 데 필요한 모든 코드가 삽입되었습니다. 새 콘솔 앱을 만들고 해당 코드를 복사하여 붙여 넣기 만하면됩니다. – Rzassar

+0

죄송합니다. 완전히 놓쳐 버렸습니다! – Rok

관련 문제