Tuesday 1 November 2011

XML Serialisation of hierarchy in C#

Yesterday was a BAD class :-(
I had the students to go and research out how to use the build in XML serialisation functions in C#, and we were going to use them to to covert all our message classes into XML for sending over the network.
I went to class, we all started coding...

public class SomeData 
{ 
    public int a; 
    public float b; 
    public string c; 
} 

// create new object and populate myData data 
SomeData myData = new SomeData(); 
myData.a = 5; 
myData.b = 8.8f; 
myData.c = "MeString"; 

// Serialization - convert to XML 
XmlSerializer sendSerializer = new XmlSerializer(typeof(SomeData)); 
StreamWriter myWriter = new StreamWriter(@"savingXML.xml"); 
sendSerializer.Serialize(myWriter, myData); 
myWriter.Close(); 
 
// Deserialization - convert back to a structure 
XmlSerializer revSerializer = new XmlSerializer(typeof(SomeData)); 
FileStream myFileStream = new FileStream(@"savingXML.xml", FileMode.Open); 
myData = (SomeData)revSerializer.Deserialize(myFileStream); 

It all coming together so well until...
<Insert dramatic music here>
I went on with the second part which was to have multiple objects types being serialised.

This is when it all fell apart


The problem
Look back the previous code, do you see when the XmlSerializer is being created it needs a type. You put in the wrong type and it just throws an exception.  I tried using typeof(Object), I tried base classes, and all other things. Eventually I found a site which explained it indirectly.

How To Solve the issue
The XmlSerializer will accept a type and an array of types, and it accept any of the types specified.
So this works:
public class SomeDataA{...}
public class SomeDataB{...}
public class SomeDataC{...}


// create new object and populate myData data 
SomeDataA myDataA = new SomeDataA(); 
SomeDataB myDataB = new SomeDataB(); 
SomeDataC myDataC = new SomeDataC(); 

// Serialization - convert to XML 
XmlSerializer sendSerializer = new XmlSerializer(typeof(SomeDataA),new Type[]{typeof(SomeDataB),typeof(SomeDataC)}); 
StreamWriter myWriter = new StreamWriter(@"savingXML.xml"); 
sendSerializer.Serialize(myWriter, myDataA); 
sendSerializer.Serialize(myWriter, myDataB); 
sendSerializer.Serialize(myWriter, myDataC); 
myWriter.Close(); 
 
// and the same for Deserialization

It also means that I can now easily have a whole hierarchy provided I know all the classes.
public class Base{...}
public class Derived1: Base{...}
public class Derived2: Base{...}

// Deserialization - convert back to a structure 
XmlSerializer revSerializer = new XmlSerializer(typeof(Base),new Type[]{typeof(Derived1),typeof(Derived2)}); 
FileStream myFileStream = new FileStream(@"savingXML.xml", FileMode.Open); 
Base b = (Base)revSerializer.Deserialize(myFileStream); 
if (b is Derived1)
{
  Derived1 d1=(Derived1)b;
  // do stuff with d1
}
else if (b is Derived2)
{
  Derived2 d2=(Derived2)b;
  // do stuff with d2
}

Conclusion
In order to use the C# XmlSerializer, you need to have specify all possible classes which could be used. This is a bit of a bind, but know I know about the issue, I won't fall foul of it again
I'm sure the Java XmlSerializer doesn't have this funny issue. But its not the total show stopper, just an annoyance, and it messed up my class yesterday.
So next week, I need to be a bit better prepared..

Happy Coding:
Mark

No comments:

Post a Comment