help me "dry" out this .net XML serialization code
- by Sarah Vessels
I have a base collection class and a child collection class, each of which are serializable. In a test, I discovered that simply having the child class's ReadXml method call base.ReadXml resulted in an InvalidCastException later on. First, here's the class structure:
Base Class
// Collection of Row objects
[Serializable]
[XmlRoot("Rows")]
public class Rows : IList<Row>, ICollection<Row>, IEnumerable<Row>,
IEquatable<Rows>, IXmlSerializable
{
public Collection<Row> Collection { get; protected set; }
public void ReadXml(XmlReader reader)
{
reader.ReadToFollowing(XmlNodeName);
do
{
using (XmlReader rowReader = reader.ReadSubtree())
{
var row = new Row();
row.ReadXml(rowReader);
Collection.Add(row);
}
} while (reader.ReadToNextSibling(XmlNodeName));
}
}
Derived Class
// Acts as a collection of SpecificRow objects, which inherit from Row. Uses the same
// Collection<Row> that Rows defines which is fine since SpecificRow : Row.
[Serializable]
[XmlRoot("MySpecificRowList")]
public class SpecificRows : Rows, IXmlSerializable
{
public new void ReadXml(XmlReader reader)
{
// Trying to just do base.ReadXml(reader) causes a cast exception later
reader.ReadToFollowing(XmlNodeName);
do
{
using (XmlReader rowReader = reader.ReadSubtree())
{
var row = new SpecificRow();
row.ReadXml(rowReader);
Collection.Add(row);
}
} while (reader.ReadToNextSibling(XmlNodeName));
}
public new Row this[int index]
{
// The cast in this getter is what causes InvalidCastException if I try
// to call base.ReadXml from this class's ReadXml
get { return (Row)Collection[index]; }
set { Collection[index] = value; }
}
}
And here's the code that causes a runtime InvalidCastException if I do not use the version of ReadXml shown in SpecificRows above (i.e., I get the exception if I just call base.ReadXml from within SpecificRows.ReadXml):
TextReader reader = new StringReader(serializedResultStr);
SpecificRows deserializedResults = (SpecificRows)xs.Deserialize(reader);
SpecificRow = deserializedResults[0]; // this throws InvalidCastException
So, the code above all compiles and runs exception-free, but it bugs me that Rows.ReadXml and SpecificRows.ReadXml are essentially the same code. The value of XmlNodeName and the new Row()/new SpecificRow() are the differences. How would you suggest I extract out all the common functionality of both versions of ReadXml? Would it be silly to create some generic class just for one method? Sorry for the lengthy code samples, I just wanted to provide the reason I can't simply call base.ReadXml from within SpecificRows.