I'm trying to implement IXmlSerializable interface in a Collection of T where T is an abstract class. My scenario is this:
- I've got a abstract class BaseClass which implements IXmlSerializable
- Two derived clases (Deriv01, Deriv02) which inherits from BaseClass and overrides the methods to proper implementation of WriteXml and ReadXml
- 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();
}