How to implement IXmlSerializable correctly for a ICollection<T> where T is an abstract class?

306 views Asked by At

I'm trying to implement IXmlSerializable interface in a Collection of T where T is an abstract class. My scenario is this:

  1. I've got a abstract class BaseClass which implements IXmlSerializable
  2. Two derived clases (Deriv01, Deriv02) which inherits from BaseClass and overrides the methods to proper implementation of WriteXml and ReadXml
  3. A Collection of BaseClass (BaseClassCollection) which is a ICollection and also implements IXmlSerializable

The serialization of the collection works fine but i'm stuck with the deserialization, I don't know how to implement it and I would like your help with it.

This is my implementation:

[XmlInclude(typeof(Deriv01))]
[XmlInclude(typeof(Deriv02))]
[XmlType("base")]
public abstract class BaseClass : IXmlSerializable
{
    private int _a;
    private string _b;

    public int A
    {
        get { return this._a; }
    }
    public string B
    {
        get { return this._b; }
    }

    protected BaseClass()
    {
        this._b = string.Empty;
    }
    protected BaseClass(int a, string b)
    {
        this._a = a;
        this._b = !string.IsNullOrEmpty(b) ? b : string.Empty;
    }

    protected virtual void WriteXmlAttributes(XmlWriter writer)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        writer.WriteAttributeString("a", XmlConvert.ToString(this._a));
    }
    protected virtual void WriteXmlElements(XmlWriter writer)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        writer.WriteStartElement("b");
        writer.WriteString(this._b);
        writer.WriteEndElement();
    }
    protected virtual void ReadXmlAttributes(XmlReader reader)
    {
        if (reader == null) throw new ArgumentNullException("reader");
        int a;
        this._a = int.TryParse(reader["a"], out a) ? a : 0;
    }
    protected virtual void ReadXmlElements(XmlReader reader)
    {
        if (reader == null) throw new ArgumentNullException("reader");

        reader.Read();
        if (!reader.IsStartElement("b")) return;
        this._b = reader.ReadString();
        reader.ReadEndElement();
    }

    #region Implementation of IXmlSerializable
    public XmlSchema GetSchema()
    {
        return null;
    }
    public void ReadXml(XmlReader reader)
    {
        if (reader == null) throw new ArgumentNullException("reader");

        ReadXmlAttributes(reader);
        ReadXmlElements(reader);
    }
    public void WriteXml(XmlWriter writer)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        WriteXmlAttributes(writer);
        WriteXmlElements(writer);
    }
    #endregion
}

[XmlType("deriv01")]
public class Deriv01 : BaseClass
{
    private int _c;

    public int C
    {
        get { return this._c; }
    }

    public Deriv01()
    { }
    public Deriv01(int a, string b, int c)
        : base(a, b)
    {
        this._c = c;
    }

    protected override void WriteXmlAttributes(XmlWriter writer)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        base.WriteXmlAttributes(writer);
        writer.WriteAttributeString("c", XmlConvert.ToString(this._c));

        writer.WriteAttributeString("xsi", "type", "http://www.w3.org/2001/XMLSchema-instance", "deriv01");
    }
    protected override void ReadXmlAttributes(XmlReader reader)
    {
        if (reader == null) throw new ArgumentNullException("reader");
        base.ReadXmlAttributes(reader);
        int c;
        this._c = int.TryParse(reader["c"], out c) ? c : 0;
    }
}

[XmlType("deriv02")]
public class Deriv02 : BaseClass
{
    private int _d;

    public int D
    {
        get { return this._d; }
    }

    public Deriv02()
    {
    }
    public Deriv02(int a, string b, int d)
        : base(a, b)
    {
        this._d = d;
    }
    protected override void WriteXmlElements(XmlWriter writer)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        base.WriteXmlElements(writer);
        writer.WriteElementString("d", XmlConvert.ToString(this._d));
    }
    protected override void ReadXmlElements(XmlReader reader)
    {
        if (reader == null) throw new ArgumentNullException("reader");
        base.ReadXmlElements(reader);
        int d;
        if (!reader.IsStartElement("d")) return;
        this._d = int.TryParse(reader.ReadString(), out d) ? d : 0;
        reader.ReadEndElement();
    }
    protected override void WriteXmlAttributes(XmlWriter writer)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        base.WriteXmlAttributes(writer);
        writer.WriteAttributeString("xsi", "type", "http://www.w3.org/2001/XMLSchema-instance", "deriv02");
    }
}

[XmlRoot("elementos")]
public class BaseClassCollection : ICollection<BaseClass>, IXmlSerializable
{
    private List<BaseClass> _elementos = new List<BaseClass>();

    public BaseClass this[int index]
    {
        get { return this._elementos[index]; }
    }

    public BaseClassCollection()
    { }

    #region Implementation of ICollection<BaseClass>
    public void Add(BaseClass item)
    {
        if (this._elementos.Contains(item)) return;
        this._elementos.Add(item);
    }
    public void Clear()
    {
        this._elementos.Clear();
    }
    public bool Contains(BaseClass item)
    {
        return this._elementos.Contains(item);
    }
    public void CopyTo(BaseClass[] array, int arrayIndex)
    {
        this._elementos.CopyTo(array, arrayIndex);
    }
    public bool Remove(BaseClass item)
    {
        return this._elementos.Remove(item);
    }
    public int Count
    {
        get { return this._elementos.Count; }
    }
    public bool IsReadOnly
    {
        get { return false; }
    }
    #endregion

    #region Implementation of IEnumerable
    public IEnumerator<BaseClass> GetEnumerator()
    {
        foreach (BaseClass elemento in this._elementos)
        {
            yield return elemento;
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    #endregion

    #region Implementation of IXmlSerializable
    public XmlSchema GetSchema()
    {
        return null;
    }
    public void ReadXml(XmlReader reader)
    {
        if (reader == null) throw new ArgumentNullException("reader");

        XmlSerializer inner = new XmlSerializer(typeof(BaseClassCollection));
        reader.Read();
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            //This line don't work
            BaseClass item = (BaseClass) inner.Deserialize(reader);
            this._elementos.Add(item);
        }
        reader.ReadEndElement();
    }
    public void WriteXml(XmlWriter writer)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
        writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");

        writer.WriteAttributeString("cont", XmlConvert.ToString(this._elementos.Count));

        foreach(BaseClass item in this._elementos)
        {
            writer.WriteStartElement("elemento");
            item.WriteXml(writer);
            writer.WriteEndElement();
        }
    }
    #endregion
}


public void ReadXml(XmlReader reader)
{
    if (reader == null) throw new ArgumentNullException("reader");

    BaseClass item = null;
    reader.Read();
    while (reader.NodeType != XmlNodeType.EndElement)
    {
       string type = reader["type", "http://www.w3.org/2001/XMLSchema-instance"];
       switch (type)
       {
           case "deriv01":
               item = new Deriv01();
               break;
           case "deriv02":
               item = new Deriv02();
               break;
       }
       if (item == null) continue;
       item.ReadXml(reader);
       this._elementos.Add(item);
       reader.ReadEndElement();
   }
   reader.ReadEndElement();
} 
0

There are 0 answers