The original article at our homepage.
Introduction
While developing for Keldyn Interactive (former Furie Entertainment), we saw the need for a good dynamic serialization method which would be usable during development, when code changes rapidly. No matter how much the code changes, we always want to be able to restore the previously serialized data. Therefore we developed our own formatter, which we will now share with you.
The XmlFormatter
is a .NET formatter (IFormatter
) which simply put can serialize an object into an XML document or the other way around; deserialize an object from an XML document. Although there already exist several other alternatives, this XmlFormatter
focuses on being practical for in-development projects. The most important feature is that the document can be loaded in most cases even though the source code has been changed since the object was serialized. This means that you can store your objects to the disk, make changes to the source code, and then load the objects back into the program again. However, at times the source code will be so different from when the object was serialized that the serializer won't be able to deserialize it properly. For this, we have designed the XML format to be easily human editable, so you can simply open up the XML document and change it so that it works again. This is especially useful if the data is critical and you "just have to get it into the program again" (which would be impossible if you used for example the binary formatter).
Usage Example
To use the formatter, we first need something to serialize. This is a simple class to demonstrate some of the features, although the formatter handles most of the things any other IFormatter
handles.
[Serializable]
class Test
{
public String String { get; set; }
int integer = 0;
public int Integer { get { return integer; } set { integer = value; } }
public List<Test> Children { get; set; }
}
Next, we demonstrate how to use the formatter to serialize and deserialize.
Test o = new Test
{
String = "MyTest",
Integer = 5,
Children = new List<Test>
{
new Test { String = "Child1" },
new Test { String = "Child2" }
}
};
XmlFormatter formatter = new XmlFormatter();
MemoryStream m = new MemoryStream();
formatter.Serialize(m, o);
m.Position = 0;
Test d = (Test)formatter.Deserialize(m);
Document Persistence (Optional Feature)
If the serialized objects are version controlled, you generally want the documents to change as little as possible when you load, update and then re-serialize them. To ensure this, we have the PersistenceData
property in the XmlFormatter
. When you deserialize, this object is created and you have to store it somewhere, and later assign it to the PersistanceData
property again. This will minimize the changes done in the document. Note that this is an optional feature.
Test d = (Test)formatter.Deserialize(s);
XmlFormatterPersistenceData p = formatter.PersistenceData;
formatter.PersistenceData = p;
formatter.Serialize(m, d);
Features
- Stores the objects in human readable XML, which means that you can easily edit your stored resources.
- A very generous type and field name resolver, which means that you can serialize an object, change your source code and then load the object again, and in most cases it will work. Fields and properties that have been removed will be ignored, new ones will have their default value.
- Lists, Arrays and Dictionaries are all handled explicitly in the formatting to give an even cleaner XML document.
- Is culture invariant, i.e. it doesn't matter if you store the data on a Swedish system and then open it on an American system.
- Version control friendly (Subversion, Git, Darcs, etc.). Minimal changes are ensured to occur in a re-serialized document, especially if you use the document persistence feature.
- You can specify your own error callback function. The default behavior is to throw an exception, but you may want to handle errors in the XML files in other ways. Note though that this feature is somewhat incomplete.
Limitations
- In spite of how a formatter "should" work, we construct objects during deserialization by calling their constructor. We found this to be useful in a scenario where you want to reset parts of the class; all you have to do is to delete those elements in the XML file and those properties or fields will be reassigned their default value.
- The
SurrogateSelector
is currently not implemented.
Alternatives
This is nowhere near an extensive list of XML serializers, but these are some of the alternatives to our class, and what we feel are their limitations compared to ours.
System.Xml.Serialization.XmlSerializier
: The problem with this class is that it does not support the ISerializable
interface and Serializable
attribute, and that it doesn't really support very complex scenarios. - Patrick Boom's XMLFormatter: This formatter needs to know the type of the object we are trying to deserialize. This can be a problem if we work with interfaces and polymorphic classes.
System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: The output of this formatter is not very human readable and thus is hard to edit. - YAXLib: This library is more targeted towards generating clear and readable XML documents. Does not support the
IFormatter
interface or the ISerializable
interface.
Conclusion
And that's it! If you have any questions or find any bugs, don't hesitate to write a line below or send us an email.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.