Last
month, I blogged about XmlSerializer, and the constraints it imposes on the
.NET types you'd like to map onto XML structure. I was recently reminded of
another limitation of XmlSerializer: it doesn't let you switch your
type mappings, on the fly -- for example, in response to a version
attribute. And yet. A great many XML document formats use just such
an attribute! Here's an example, from Visual Studio's own .csproj file format
-- it seems they like to serialize both the product- and schema-version numbers,
for good measure:
<VisualStudioProject>
<CSHARP
ProjectType
= "Local"
ProductVersion
= "7.10.3077"
SchemaVersion
= "2.0"
...
Why doesn't XmlSerializer allow us to switch our type mappings, after we see the version number? The reason is simple, although not immediately apparent: XmlSerializer is a compiler.
Ever wonder why you must specify the root element's .NET type, at instantiation-time?
And what is that extraTypes parameter all about -- why doesn't XmlSerializer
simply call Object.GetType() at run-time, and do the right thing?
It's because XmlSerializer wants to generate the complete code for serialization,
beforehand -- so it's got to know the complete set of types it can expect
to face.
This design offers fantastic throughput, for high-volume serialization scenarios like web service backends -- but it comes at the cost of some run-time flexibility, for scenarios like deserialization of versioned document types.
Now, if your XML schema has only trivial differences among versions (eg: the addition of an attribute or element, here or there) you can probably just get away with using the latest version's type mappings -- when deserializing an older instance document, the missing elements and attributes will be initialized to their default values -- no exceptions are thrown. But for less trivial changes in schema, there's just no easy way to tell the XmlSerializer "hey, if you see a version attribute with a value less than 4.7, back up and start over with this older set of .NET types".
Of course, it's a free country: you can use XmlDocument or XmlReader to peek ahead for the version attribute, then back up and start over in earnest with a properly initialized XmlSerializer -- but just how terribly inefficient that is depends on where you're getting your XML from, and how large it is. FileStream? Not too bad. NetworkStream? Terrible.
