Dan's getting some welcome assistance from Scott Hanselman with some XML Serialization troubles.
I've been occasionally sticking my oar in to help Dan out with this puzzling little foible of the .NET XML serialization stack for a couple of weeks now, and I can say it really does look like a bug to me. At root, we've got a perfectly valid, normative XML Schema that declares an unambiguous XML vocabulary; and we've got a set of classes output from xsd.exe based upon that schema, that the XML Serializer serializes to XML documents which don't always conform to the original schema. That's got to be a bug. But where? Is it in xsd.exe? Is it in the classes xsd.exe generates? Is it in the serializer that generates the custom serialization code based on those classes? Or is it in the classes that the serializer generates? Or is it in Dan's code?
Now today, with Scott's help, Dan's managed to narrow down what's going on to the ordering of a series of if statements in the serialization code generated by XmlSerializer the first time you ask it to initialise itself for a particular type.
What’s immediately apparent is that neither set of if statements here match the order in which the stack is written in the source code and, ironically, the if statement for hello is at the bottom of the stack in the right hand pane where the elementattribute for hello was on the top of the stack in the original code. To see if this was an arbitrary placing of the if statements in the serializer dll, I moved the hello attribute up the stack one place at a time, rebuilt and viewed the temp dll code and the order of the ifs never matched the attribute stack. More annoyingly, I didn't (through luck or otherwise) get the if statement for hello to appear as the last of the if statements in the DLL again which would produce exactly the required results.
[Via Dan's Archive]
Now this rings a bell. Specifically, not too long ago K. Scott Allen (everyone's called Scott today) blogged about how "Microsoft decided to introduce some randomization in reflection methods like GetFields". Well, deep down inside the XmlSerializer (and a deep-dive expedition with Lutz Roeder's Reflector confirms this), we find some calls to GetCustomAttributes() are populating the arrays that ultimately get iterated over to generate those if statements. How else is it going to analyse the type it's been handed to generate that serialization code but by using reflection?
Now granted, there's not anything explicit in the documentation for MemberInfo.GetCustomAttributes() that indicates that it deliberately shuffles the cards before handing them back to you (and reflector draws a blank at the managed/unmanaged code boundary inside System.Reflection), but it would be consistent to assume that it is not going to return them in sourcecode order. There's little to suggest that we should assume sourcecode order would even be preserved by the C# compiler in constructing the MSIL.
Which leaves us back at square one, with no way to have any guaranteed influence over exactly what order those if statements get generated in. We can't, then, blame xsd.exe for the order it puts the attributes in - that doesn't seem to make that much difference to the result. We can maybe blame the XML Serializer for not caring that the order of its if statements is significant.
Let's hope Dan gets a resolution to this one soon - it'll be interesting to see what he finds.