help me "dry" out this .net XML serialization code

Posted by Sarah Vessels on Stack Overflow See other posts from Stack Overflow or by Sarah Vessels
Published on 2010-02-08T17:49:59Z Indexed on 2010/06/02 16:04 UTC
Read the original article Hit count: 306

Filed under:
|
|
|

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.

© Stack Overflow or respective owner

Related posts about c#

Related posts about refactoring