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 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 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.
what is the problem? and how can i fix it?
---------------EDIT----------------------
i know that problem is in IXmlSerializable.ReadXml()
implementation. 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();
to the end of ReadXml
fixes it, but is a bit ugly; ReadSubtree()
may be safer.
Frankly, implementing IXmlSerializable
correctly and robustly is hard. I always advise against it.