The best feature about C# has got to be Xml Serialization.
Creating an Xml reader/writer in C++ using MSXML or LibXml takes significant time and debugging. Creating the same Xml reader/writer in C# using classes is very easy. Admittedly, if I am using C++, I have no problems using LibXml, but if given a choice, I'd use C# first.
To make a class Xml Serializable, you need to:
- make the class public, and
- give it the Serializable attribute.
The follow class can be read/written to Xml:
[Serializable]
public class Family
{
}
This class won't do anything, but you can use the follow code to write it to file:
Family f = new Family();
// TODO: Fill the family object
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Family));
TextWriter writer = new StreamWriter("Family.xml");
xmlSerializer.Serialize(writer, f);
writer.Close();
and the following code to read from file:
XmlSerializer xs = new XmlSerializer(typeof(Family));
TextReader reader = new StreamReader("Family.xml");
Family f = (Family)xs.Deserialize(reader);
The resulting Xml file will look like this:
<?xml version="1.0" encoding="utf-8"?>
<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
Pretty basic and not much fun.
Every family I know has a family name, so let's add a name to the family:
[Serializable]
public class Family
{
public string Name { get; set; }
}
(Please note that I am using C# 3.5 short-notation for members.)
If we set the family name and serialize it, we'll get the following:
<?xml version="1.0" encoding="utf-8"?>
<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Smith</Name>
</Family>
Notice that the Name member of Family became a child element of Family in the Xml tree. This is the default behaviour of all public members. By default, C# will serialize all public members of a class as sub-elements.
In my case, I'd prefer Name to be an attribute of family instead of a sub-element. To do this, I use the [XmlAttribute] attribute on the Name member:
[Serializable]
public class Family
{
[XmlAttribute]
public string Name { get; set; }
}
to get:
<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Name="Smith" />
This is now more to my liking.
Let's add some family members to this family. First, define a family member class:
[Serializable]
public class FamilyMember
{
public string Name { get; set; }
public short Age { get; set; }
}
and add a list of family members to our family class:
private List<FamilyMember> _members = new List<FamilyMember>();
public List<FamilyMember> Members
{
get { return _members; }
set { _members = value; }
}
If we add some members to our family, and serialize, we get the following:
<Family xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Name="Smith">
<Members>
<FamilyMember>
<Name>John</Name>
<Age>51</Age>
</FamilyMember>
<FamilyMember>
<Name>Mary</Name>
<Age>50</Age>
</FamilyMember>
</Members>
</Family>
You'll notice that we have 2 family members each with their own data.
In part 2, we will specialize the family members into derived classes of FamilyMember.