Following on from my previous question I have been working on getting my object model to serialize to XML. But I have now run into a problem (quelle surprise!).
The problem I have is that I have a collection, which is of a abstract base class type, which is populated by the concrete derived types.
I thought it would be fine to just add the XML attributes to all of the classes involved and everything would be peachy. Sadly, thats not the case!
So I have done some digging on Google and I now understand why it's not working. In that the XmlSerializer
is in fact doing some clever reflection in order to serialize objects to/from XML, and since its based on the abstract type, it cannot figure out what the hell it's talking to. Fine.
I did come across this page on CodeProject, which looks like it may well help a lot (yet to read/consume fully), but I thought I would like to bring this problem to the StackOverflow table too, to see if you have any neat hacks/tricks in order to get this up and running in the quickest/lightest way possible.
One thing I should also add is that I DO NOT want to go down the XmlInclude
route. There is simply too much coupling with it, and this area of the system is under heavy development, so the it would be a real maintenance headache!
Best Answer
Problem Solved!
OK, so I finally got there (admittedly with a lot of help from here!).
So summarise:
Goals:
Identified Issues/Points to Note:
The Solution
I created a generic class, in which you specify the generic type as the abstract type you will be working with. This gives the class the ability to "translate" between the abstract type and the concrete type since we can hard-code the casting (i.e. we can get more info than the XmlSerializer can).
I then implemented the IXmlSerializable interface, this is pretty straight forward, but when serializing we need to ensure we write the type of the concrete class to the XML, so we can cast it back when de-serializing. It is also important to note it must be fully qualified as the assemblies that the two classes are in are likely to differ. There is of course a little type checking and stuff that needs to happen here.
Since the XmlSerializer cannot cast, we need to provide the code to do that, so the implicit operator is then overloaded (I never even knew you could do this!).
The code for the AbstractXmlSerializer is this:
So, from there, how do we tell the XmlSerializer to work with our serializer rather than the default? We must pass our type within the Xml attributes type property, for example:
Here you can see, we have a collection and a single property being exposed, and all we need to do is add the type named parameter to the Xml declaration, easy! :D
NOTE: If you use this code, I would really appreciate a shout-out. It will also help drive more people to the community :)
Now, but unsure as to what to do with answers here since they all had their pro's and con's. I'll upmod those that I feel were useful (no offence to those that weren't) and close this off once I have the rep :)
Interesting problem and good fun to solve! :)