I have a class containing a readonly string. Thus I need to manually handle xmlserialization. But it seems that using this class in a grander setting with automatic xml serialization ruins the deserialization process.
First my readonly class
public class RO : IXmlSerializable
{
public string Name { get; private set; }
// for serialization
protected RO(){}
public RO(string name)
{
this.Name = name;
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
Name = reader.ReadString();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteString(Name);
}
}
then a wrapper class holding my readonly object and some value
public class Holder
{
public RO a;
public decimal b;
}
and now I serialize and deserialize an instance of the holder
class Program
{
static void Main(string[] args)
{
XmlSerializer xml = new XmlSerializer(typeof(Holder));
var s = new StringWriter();
var holder = new Holder() { a = new RO("foo"), b = 234 };
xml.Serialize(s, holder);
string ss = s.ToString();
Console.WriteLine("*****");
Console.WriteLine(ss);
Console.WriteLine("*****");
holder = (Holder) xml.Deserialize(new StringReader(ss));
Console.WriteLine(holder.a.Name);
Console.WriteLine(holder.b);
}
}
on the screen is a nice-looking xml
*****
<?xml version="1.0" encoding="utf-16"?>
<Holder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
www.w3.org/2001/XMLSchema">
<a>foo</a>
<b>234</b>
</Holder>
*****
but when we print the values a and b we get 0 for our decimal.. despite we see the 234 in the xml
foo
0
I suspect the problem is that you're not reading to the end of the containing element - I suspect you want:
public void ReadXml(XmlReader reader)
{
Name = reader.ReadElementContentAsString();
}
The documentation for ReadXml
states:
When this method is called, the reader is positioned on the start tag that wraps the information for your type. That is, directly on the start tag that indicates the beginning of a serialized object. When this method returns, it must have read the entire element from beginning to end, including all of its contents. Unlike the WriteXml method, the framework does not handle the wrapper element automatically. Your implementation must do so. Failing to observe these positioning rules may cause code to generate unexpected runtime exceptions or corrupt data.
ReadString
will just read a string and stop when it gets to the end element tag; ReadElementContentAsString
will position the reader after the end element tag.
I've just tried the above code with your sample, and it solves the problem there, at least.
See more on this question at Stackoverflow