As people who follow me on twitter might know, I was working on a reflection tutorial for C#/XNA. However I got a bit carried away with the XML Serialization.
So here’s first an XML Serialization tutorial.
In previous tutorials/code-snippets I showed how to use the intermediate serializer. But for the tutorial I wanted to serialize all the XML by hand so that it would be crystal clear for anyone following the tutorial what was going on.
Quickly I coded up the following interface:
This code should be pretty self explanatory. Remember that an XmlDocument object is also an XmlNode. So for the root object you can pass your newly constructed XmlDocument as parent node.
I quickly created 3 classes:
-Block, a simple class with texture, position scale and tinting with the ability to draw itself.
-RotatbleBlock, child class of block, with the ability to rotate itself.
-Scene, a class containing a Block that draws all the blocks.
Both Scene and Block, and thus RotatableBlock, implement ISerializable.
Serializing is now easy (only relevant bits here):
In our static Serializer class we do this:
Take extra care to set the culture to invariant temporarily so that we don’t get different results depending on our computer’s localization settings.
Scene is serialized this way:
As you can see the object serialized just creates a new child node in the parent node. It’s name is it’s exact full namespace name (this will be important later).
The serialization code for Block is pretty straightforward too.
Where it get’s interesting is in the serialization code of RotatableBlock:
As you can see we create an element for our object as normal. We also append anything we want to remember in child nodes in the XML. The interesting part is that we pass the newly created node as a root node for the Serialize method of the base class.
This approach generates the following XML:
(We saved a Scene which had an array of blocks, which contained one normal Block and one RotatableBlock using our Serializer’s Save method).
Recreating the Scene, Block and RotatableBlock from this XML file is fairly easy. Let’s first declare a Load method in our Serializer.
As you can see we load an XMLDocument normally. And start deserializing the first child of the document (the element in our case). I've added a little helper method (GetObjectFromNode) that actually does a lot of work. Via reflection it looks up the class stored in the name of the node. At first it will find "TutorialEngine.Scene" and it will thus create an instance of our Scene class.
After this we simply call Deserialize on our newly instantiated Scene object, giving it the XMlDocument and the node that represents the Scene itself.
Deserializing a Scene is now easy:
See that we keep using the Serializer.GetObjectFromNode helper method to instantiate a block. Note that a RotatableBlock can be casted to a Block (we are using polymorphism here again). But that when deserialzing the overriden method in RotatableBlock will be used.
The deserialization code for a block is easy (and a bit dull)
Note that we are using the GameServices class from a previous tutorial to get easy access to the ContentManager.
Now the interesting part is again in how we handled Inheritance in RotatableBlock, so let’s take a look at that code:
As you can see we first set the rotation variable with the data saved in our XMLNode. However the special thing is that we now just deserialize the rest of our RotatableBlock data by calling the base.Deserialize method on the element inside our element. This way we don't have to duplicate any code.
As you can see this is a pretty neat and clean way of writing your own XML Serialization code. It will save you a lot of work, and a lot of errors compared to writing the same boring serialization code for each object. If you have problems understanding inheritance and polymorphism I suggest that you quickly brush up on those techniques as they are crazy powerful and a must for every developer that works with an object oriented language as C#.
Be aware that there are multiple ways to automatically serialize your data, like the previously mentioned IntermediateSerializer, or using Xna.BinaryWriter.
I believe that the above code is as Xbox360 compatible as the other ways, and the nice thing is, is that it will also work when not using XNA at all :).
Anyway, I hope you liked this. Stay tuned for the reflection tutorial for which I wrote this (yeah I did get carried away).