I know that Jeff Atwood over at Coding Horror isn’t very fond of XML, but personally, I have grown to love it. Well, not XML as such, but the ease of serializing and de-serializing C# classes to XML and back provided by Visual Studio.
Jeff’s complaints seem to be all about the difficulty that humans (well, programmers, anyway) have in reading all those angle brackets. To me, this seems to be beside the point, since humans aren’t really supposed to be reading XML anyway – computers are. It’s just a nice side-benefit that we programmers can look at XML files with a text editor and generally get a pretty good sense of what is going on.
Anyway, what I love about serializing to XML is the way that in C# you can build up a very complex object, with nested lists of diverse objects and such, and yet just blatt it all out to a file, or send it by MSMQ, and just magically read it back and have that fully complex object back again, without any need to spend time coding to parse it all in or out.
For example, in one of the applications I built for Kaleidio, we are simulating electronic transactions between companies. So I have a class called ‘Company’, name, address, etc, as you would expect it; but among other complexities, the company class also includes an array of storage locations. Each storage location has a list of products being stored, each with its own information about price, unit size, bar-code, etc. Obviously, these are ‘toy’ companies with far less complexity than the real thing; but nevertheless, they are complex objects.
With serialization, I can just set up and save an entire company object to disk, or pick it up and despatch it to another computer via MSMQ (or SOAP, or whatever).
There’s a great article with some really good utility routines for reading and writing serialized XML here at Code Project. If you base your code on these routines, you can write code like this:
var myCompany = new Company();
//fill in company details, add storage locations,
//fill locations with products, etc.
ToXMLfile(@"C:\temp\company.xml", myCompany);
//then, later:
var loadedCompany = (Company)FromXMLfile(@"C:\temp\company.xml",
typeof(Company);
//now work with the company again. |
To make this all work well you generally have to assign attributes to members of your classes to give the serializer hints as to how you want the XML to work.
public class Company
{
[System.Xml.Serialization.XmlAttribute()]
public string Name = "MyBusiness";
[System.Xml.Serialization.XmlElement()]
public string Address= "41 Smith Street, Collingwood, Vic 3066";
//.... |
This creates XML like:
<Company Name="MyBusiness">
<Address>41 Smith Street, Collingwood, Vic 3066</Address>
....
</Company> |
I have used this a lot in the last 6 or 7 years, but I have to admit that it’s a feature of Visual Studio that I have basically taken for granted, and only rarely had to worry about the implementation. In other words, I haven’t really researched it and thought about it in any detail, just used it at a basic level. I’m guessing that most practicing programmers use many such language features in the same way.
But it’s when what you have taken for granted suddenly causes you grief that you have to start hitting the F1 key (or, more usefully, googling) to get some answers.
For example, there are some kinds of data type which you can’t serialize directly, such as TimeSpan. So you have to use a workaround like this:
[System.Xml.Serialization.XmlElement]
public long DurationTicks;
[System.Xml.Serialization.XmlIgnore]
public TimeSpan Duration
{
get { return new TimeSpan(DurationTicks); }
set
{
DurationTicks = value.Ticks;
}
} |
Note that one of the disadvantages of serialization is that any value to be serialized must be marked as public, so DurationTicks above is visible as a member of the class to which it belongs, even though you don’t really want it messed with directly.
Where I have gotten myself into difficulties in the past is where you want a class to be able to have a member which may be of various different kinds of object. They are different, but they do all inherit from a base class.
You can use a construct like this, which uses an additional class member to indicate to the serializer the type of object being included:
[System.Xml.Serialization.XmlChoiceIdentifier("ControlType")]
[System.Xml.Serialization.XmlElement(Type = typeof(VideoControl))]
[System.Xml.Serialization.XmlElement(Type = typeof(ImageControl))]
[System.Xml.Serialization.XmlElement(Type = typeof(FlashControl))]
public Control ControlObj = null;
/// <summary>
/// Identifies the type of control being sent.
/// </summary>
[System.Xml.Serialization.XmlIgnore]
public ControlTypes ControlType = ControlTypes.None; |
Note the XmlIgnore tag, which tells the serializer not to explictly include this property in the XML.
But I struggled for a while to figure out what to do when the class I was trying to serialize had a member which was a list of such variable objects.
For example in one of my shareware projects, I have an object which includes such a list (a List<FileRecord>, to be specific). Mostly this list contains plain FileRecord objects, but I also have a class called CDTrackRecord which inherits from FileRecord. For quite a while I couldn’t figure out how to correctly serialize a class with a list which included one or more such inherited objects.
I’m still not sure if this is the best solution, but I discovered that you can use an XmlInclude attribute on the base class of list members, like this, to show it also includes the possibility of the inherited object:
[System.Xml.Serialization.XmlInclude(typeof(CDTrackRecord))]
public class FileRecord
{
//class members
} |
The class including a List<FileRecord> now serializes nicely.
Disclaimer: I don’t claim to be any kind of programming expert, just a dumb old programmer with a passion for coding. Bear this in mind if you comment!