Menu

An XML Serialization Alternative

November 30, 2014 - .NET, C#, Programming

I’ve rambled about XML Serialization for a while, in particular, the fact that the built-in Serialization provided with .NET is problematic to use as a file format. This is primarily in relation to BASeBlock, which currently saves Level data using th BinaryFormatter- this introduces a problem as simply recompiling the program or making simple changes can break the reading of old file formats.

To combat this, I always wanted to switch to a more user-friendly or at least ‘general’ format. In this case, XML. But doing so was not entirely straightforward. For one thing, the existing IFormatter implementations required the classes to be built in a specific way- have default, public constructors, etc. These design choices would not make sense in my case- I don’t want things like Blocks to be instantiated with no arguments, since that would leave the standard properties in a state that can cause errors for other logic and if I can prevent it earlier I will do so (and I do).

I toyed with a IFormatter implementation I found online which alleged to support XML serialization via IFormatter to XML files. and it- sort of worked, but apparently has issues with Generic type definitions. It also used the older XmlSerializer whereas I typically prefer the very fluent Xml.Linq (XElement, XDocument).

The result was essentially just having to define my own small library and serialization framework with one straightforward task- it can either take a object and turn it into an XElement, or take that XElement and transform it into the object. We have two types of Objects that would need to be turned into and back from “XElement’s”. We have objects defined in classes that we are in control of and can change- thus we could implement new interfaces if needed- and we have objects either within the .NET Framework or in other libraries that we cannot change. The former seems fairly straightforward. We can solve that issue by defining a fairly straightforward interface not unlike the ISerializable interface:

--Edit--

I realized after originally posting that IXMLSerializable was a rather poor name choice, as that conflicts with the IXMLSerializable interface in the Framework. I have thus changed the class name to “IXmlPersistable” instead.

In this case, the interface defines a single method- GetXmlData, defined to return an XElement given the name to assign to that XElement Node. Like ISerializable it also has a added requirement that the class definition have a constructor that accepts a XElement which will be used to “reconstitute” the instance with the data in that XElement. This “solves” the issue of serializing our own class instances- but what about framework classes or classes in other libraries that we cannot make such changes to? In order to solve that issue I created another Interface, the IXmlPersistableProvider<T> interface:

This interface is implemented to create a class that can be defined to supprot serialization and deserialization of a given type when that type doesn’t support it. I then created a standard helper class which implemented a number of forms of this interface to serialize to and from the various framework classes, as well as methods which effectively encapsulate the logic of saving/loading to or from a given instance based on whether that type supports the interface or there is a provider. I have the Provider Dictionary initialized to the standard Providers, and there is a static method that can add new providers from external code, if desired (which I’ve called “Helpers”). By way of example, here is the code that saves a given instance to an XElement:

Essentially, if the type T is a class that implements the interface, it will use the interface method. Otherwise, it looks for a provider; if there is one present, it will use that provider’s SerializeObject interface method. otherwise, an ArgumentException is thrown.

I’ve been integrating this library into BASeBlock, by working from the bottom (top?) of the heirarchy from the least derived to the most derived, as well as adding any required providers along the way. With any luck using it this way may end up creating a “expected” XML Format for a LevelSet File, that would also make it (at least somewhat) user-editable, which would be quite cool.

Here is the source code for the library:XMLSerialization. If I get around to uploading it to a standard source control such as git I will try to remember to update this post.

Have something to say about this post? Comment!