I am trying to serialize a series of subclasses deriving from a single abstract superclass WorldObject
to XML, using the IXmlSerializable
interface. I have to use this interface, as I want the class to subscribe to some events as it is deserializing.
Using this answer, I came up with the following code:
[XmlInclude(typeof(SubType1))
,XmlInclude(typeof(SubType2))] // etc, includes all subtypes
public abstract class WorldObject : IComparable, IXmlSerializable
public void WriteXml(System.Xml.XmlWriter writer)
{
Type[] extraTypes = new Type[8];
// (...) adding types to array here
var worldObjectSerializer = new XmlSerializer(typeof(List<WorldObject>), extraTypes);
}
The last line where the XmlSerializer
is initialized throws a runtime error: System.MissingMethodException: Cannot create an abstract class 'Namespace.WorldObject'. The same error is thrown when I try to use typeof(WorldObject)
instead of typeof(List<WorldObject>)
.
I have also tried setting the XMLRoot to the same value in every class as demonstrated here, but the error persists.
I never found a way to get rid of the exception, but I found a workaround. The solution simply writes its own element wrapper with the type as its name, calls the WriteXml function and writes the end element.
foreach (WorldObject wO in list)
{
writer.WriteStartElement(wO.GetType().ToString());
wO.WriteXml(writer);
writer.WriteEndElement();
}
This allows you to deserialize the concrete implementation of the abstract class as well. The wO.GetType().ToString()
creates a string with the concrete class and namespaces. Then you can create an XmlSerializer
where the type is gleaned from the element wrapper name, like so:
Type t = Type.GetType(reader.LocalName);
XmlSerializer worldObjectSerializer = new XmlSerializer(t, new XmlRootAttribute(reader.LocalName));