简体   繁体   English

正确的序列化但不正确的反序列化

[英]correct serialize but incorrect Deserialize

consider following codes and classes: 考虑以下代码和类:

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

when i run it, an xml will generated into ser.xml like so: 当我运行它时,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">
  <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>

but it cannot correctly Deserialize the file unless i reorder the elements in the xml like so: 但是它不能正确地反序列化文件,除非我像这样对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>

note that serializer.UnknownAttribute and serializer.UnknownElement will not raise during both execution. 请注意,在两次执行期间都不会引发serializer.UnknownAttributeserializer.UnknownElement
what is the problem? 问题是什么? and how can i fix it? 我该如何解决?

---------------EDIT---------------------- - - - - - - - -编辑 - - - - - - - - - - -
i know that problem is in IXmlSerializable.ReadXml() implementation. 我知道问题出在IXmlSerializable.ReadXml()实现中。 but what kind of problem and how should i cure it? 但是什么样的问题,我应该如何解决呢?

Basically, you aren't progressing the reader to the end of the sub-tree correctly. 基本上,您没有将阅读器正确地推进到子树的末尾。 Adding reader.Read(); 添加reader.Read(); to the end of ReadXml fixes it, but is a bit ugly; ReadXml的末尾修复了它,但是有点难看; ReadSubtree() may be safer. ReadSubtree()可能更安全。

Frankly, implementing IXmlSerializable correctly and robustly is hard. 坦白地说, 正确,可靠地实现IXmlSerializable很难。 I always advise against it. 我总是建议不要这样做。

Although I would have to see your IXmlSerializable implementation, my bet would be, that your ReadXml implementation has a reversed order of processing ... eg: it first looks for element2 instead of element1. 尽管我不得不看一下您的IXmlSerializable实现,但我敢打赌,您的ReadXml实现的处理顺序相反...例如:它首先查找element2而不是element1。 If this is not it, please post your IXmlSerializable implementation. 如果不是,请发布您的IXmlSerializable实现。

EDIT 编辑

As Marc pointed out, you need to add another read. 正如Marc指出的那样,您需要添加其他内容。 Problem was, that XmlReader by calling reader.Read() processed collection entry tag, but at the end of your method, you didn't process the end tag /collection , hence another reader.Read() call. 问题是,通过调用reader.Read()来处理XmlReader来处理集合项标签,但是在方法的最后,您没有处理结束标签/ collection ,因此调用了另一个reader.Read()。 This basically prevented the deserialization to proceed correctly. 这基本上阻止了反序列化正确进行。

Generally the correct pattern for ReadXml implementation is to start with: 通常,ReadXml实现的正确模式是从以下开始:

 bool isEmpty = reader.IsEmptyElement;

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

And finish with: 并完成:

reader.ReadEndElement();

Here is also your implementation using the pattern: 这也是您使用模式的实现:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM