2

次のコードとクラスを検討してください。

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

しかし、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>

serializer.UnknownAttributeandserializer.UnknownElementは両方の実行中に発生しないことに注意してください。
何が問題ですか?どうすれば修正できますか?

---------------EDIT----------------------問題が実装
にあることはわかっています。IXmlSerializable.ReadXml()しかし、どのような問題があり、どうすれば治せますか?

4

2 に答える 2

3

基本的に、リーダーをサブツリーの最後まで正しく進めていません。reader.Read();の最後に追加するとReadXml修正されますが、少し醜いです。ReadSubtree()より安全かもしれません。

率直に言って、IXmlSerializable 正しく堅牢に実装することは困難です。私はいつもそれに対してアドバイスします。

于 2012-07-19T06:34:08.497 に答える
1

私はあなたの IXmlSerializable 実装を確認する必要がありますが、私の賭けは、あなたの ReadXml 実装の処理順序が逆になっていることです...たとえば、最初に element1 ではなく element2 を探します。そうでない場合は、IXmlSerializable の実装を投稿してください。

編集

マークが指摘したように、別の読み取りを追加する必要があります。問題は、reader.Read() を呼び出してコレクションエントリ タグを処理した XmlReader でしたが、メソッドの最後で終了タグ/collectionを処理しなかったため、別の reader.Read() 呼び出しです。これにより、デシリアライズが正しく進行できなくなりました。

一般に、ReadXml 実装の正しいパターンは、次から始めることです。

 bool isEmpty = reader.IsEmptyElement;

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

そして、次で終了します。

reader.ReadEndElement();

パターンを使用した実装も次のとおりです。

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();
}
于 2012-07-19T06:23:23.913 に答える