I have an array whose indices map back to Enum values. I would like to use the C# Xml Serialization libraries to serialize this array. However, I would like each Xml node to say the name of the Enum type that it represents. How can I do this?
Example:
public class NumberOfEmployees
{
public enum EmployeeType { Lawyer, Doctor, Engineer };
public int[] NumEmployees { get; set; }
// Constructor initializes array to size of "EmployeeType"
public NumberOfEmployees()
{
int size = Enum.GetValues(typeof(EmployeeType)).Length;
this.NumEmployees = new int[size];
}
}
Main()
{
NumberOfEmployees numEmployees = new NumberOfEmployees();
// Add doctors, lawyers, engineers, etc...
// numEmployees.NumEmployees[(int)NumberOfEmployees.Lawyer] = 3;
// numEmployees.NumEmployees[(int)NumberOfEmployees.Doctor] = 2;
// numEmployees.NumEmployees[(int)NumberOfEmployees.Engineer] = 1;
// Serialize to "file"
FileStream fs = new FileStream(file, FileMode.OpenOrCreate);
XmlSerializer xml = new XmlSerializer(typeof(NumberOfEmployees));
xml.Serialize(fs, numEmployees);
fs.Close();
}
The end result is xml that looks something like this:
<NumEmployees>
<int>3</int>
<int>2</int>
<int>1</int>
</NumEmployees>
But what I want is:
<NumEmployees>
<Lawyer>3</Lawyer>
<Doctor>2</Doctor>
<Engineer>1</Engineer>
</NumEmployees>
I can not store each number separately -- it must be an array.
Thanks.
You can implement the IXmlSerializable interface to completely customize serialization with XmlSerializer. Something similar to the following:
public class NumberOfEmployees : IXmlSerializable
{
public int[] NumEmployees { get; set; }
// Constructor initializes array to size of "EmployeeType"
public NumberOfEmployees()
{
int size = Enum.GetValues(typeof(EmployeeType)).Length;
this.NumEmployees = new int[size];
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
reader.ReadStartElement();
NumEmployees[(int)EmployeeType.Lawyer] = int.Parse(reader.ReadElementString("Lawyer"));
NumEmployees[(int)EmployeeType.Doctor] = int.Parse(reader.ReadElementString("Doctor"));
NumEmployees[(int)EmployeeType.Engineer] = int.Parse(reader.ReadElementString("Engineer"));
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("Lawyer", NumEmployees[(int)EmployeeType.Lawyer].ToString());
writer.WriteElementString("Doctor", NumEmployees[(int)EmployeeType.Doctor].ToString());
writer.WriteElementString("Engineer", NumEmployees[(int)EmployeeType.Engineer].ToString());
}
}
After you've done all that it might seem pointless to still use XmlSerializer since your class is handling all the work of serialization. It still makes sense, however, if the NumberOfEmployees is part of a larger XML structure (which I assume it is).
Also note that the code doesn't do any validation, because this is a simple example. So all three array elements will be expected to exist when the class is serialized, and all three XML elements will be expected to exist when it is deserialized.
More info on the IXmlSerializable interface is available here:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
Related
I am attempting to serialize just part of a class. I've added XML attributes to the class members so that the generated XML tags are correctly named to match a spec regardless of what my properties are named. This works fine when serializing the main class. However, if I just want to serialize part of the class, I lose the XML attributes and the names go back to their defaults. Is there a way to retain the XML attributes when serializing just part of a class?
[XmlRoot ("someConfiguration")]
public class SomeConfiguration
{
[XmlArray("bugs")]
[XmlArrayItem("bug")]
public List<string> Bugs { get; set; }
}
When I serialize the entire class, I get this (which is exactly as I would expect):
<someConfiguration>
<bugs>
<bug>Bug1</bug>
<bug>Bug2</bug>
<bug>Bug3</bug>
</bugs>
</someConfiguration>
If I attempt to just serialize the 'Bugs' part of the class, I get this (note the XML attributes that change the tag names are all ignored):
<ArrayOfString>
<string>Bug1</string>
<string>Bug2</string>
<string>Bug3</string>
</ArrayOfString>
I need to get this:
<bugs>
<bug>Bug1</bug>
<bug>Bug2</bug>
<bug>Bug3</bug>
</bugs>
How do I get the partial class to serialize with the above tags?
Or better yet, is there a way to specify tag names when serializing a simple List<object>. So that you can specify the tag used for the list instead of it using <ArrayOfobject> and specify the tag used for the array items instead of <object>?
is there a way to specify tag names when serializing a simple List.
In general, depending on the exact scenario, it may be possible to get this to work. See MSDN's How to: Specify an Alternate Element Name for an XML Stream. The example there involves overriding serialization of a specific field, but it may be possible to use the same technique to override whole type names as well.
But it seems like an awful lot of trouble to me. Instead, why not just handle the serialization explicitly:
private static string SerializeByLinqAndToString<T>(
List<T> data, string rootName, string elementName)
{
XDocument document = new XDocument(
new XElement(rootName, data.Select(s => new XElement(elementName, s))));
return SaveXmlToString(document);
}
private static string SaveXmlToString(XDocument document)
{
StringBuilder sb = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(sb,
new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
{
document.Save(xmlWriter);
}
return sb.ToString();
}
Call like this:
SomeConfiguration config = ...; // initialize as desired
string result = SerializeByLinq(config.Bugs, "bug", "bugs");
The above works only with a list of strings, or a list of types where the element content can be simply the result of calling ToString() on the instance of the type.
Using the full-blown serialization features in .NET might be worthwhile when dealing with complex types, but if all you've got is a simple list of strings, the LINQ-to-XML feature is very handy.
If you do have more complex types, you can transform each list element into an XElement for the DOM and serialize that:
private static string SerializeByLinq<T>(
List<T> data, string rootName, string elementName = null)
{
XDocument document = new XDocument(
new XElement(rootName, data.Select(t =>
ElementFromText(SerializeObject(t), elementName)
)));
return SaveXmlToString(document);
}
private static XElement ElementFromText(string xml, string name = null)
{
StringReader reader = new StringReader(xml);
XElement result = XElement.Load(reader);
if (!string.IsNullOrEmpty(name))
{
result.Name = name;
}
return result;
}
private static string SerializeObject<T>(T o)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringWriter textWriter = new StringWriter();
using (XmlWriter writer = XmlWriter.Create(textWriter,
new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
{
xmlSerializer.Serialize(writer, o,
new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty}));
}
return textWriter.ToString();
}
In this second example, you can omit the element name for the child, and it will just use whatever the type's set up to use already (e.g. the type name, or whatever [XmlRoot] is set to).
Just throwing this out there, you could wrap the List<> inside a custom class:
[XmlRoot("config")]
public class SomeConfiguration
{
[XmlElement("bugs")]
public BugList Bugs { get; set; }
[XmlElement("trees")]
public TreeList Trees { get; set; }
}
[XmlRoot("bugs")]
public class BugList
{
[XmlElement("bug")]
public List<string> Items = new List<string>();
}
[XmlRoot("trees")]
public class TreeList
{
[XmlElement("tree")]
public List<string> Items = new List<string>();
}
That will now allow you to serialize the individual Lists and they'll be rooted as you'd expect.
void Main()
{
var config = new SomeConfiguration
{
Bugs = new BugList { Items = { "Bug1", "Bug2" } },
Trees = new TreeList { Items = { "Tree1", "Tree2" } }
};
// Your config will work as normal.
Debug.WriteLine(ToXml(config)); // <config> <bugs>.. <trees>..</config>
// Your collections are now root-ed properly.
Debug.WriteLine(ToXml(config.Bugs)); // <bugs><bug>Bug1</bug><bug>Bug2</bug></bugs>
Debug.WriteLine(ToXml(config.Trees)); // <trees><tree>Tree1</tree><tree>Tree2</tree></trees>
}
public string ToXml<T>(T obj)
{
var ser = new XmlSerializer(typeof(T));
var emptyNs = new XmlSerializerNamespaces();
emptyNs.Add("","");
using (var stream = new MemoryStream())
{
ser.Serialize(stream, obj, emptyNs);
return Encoding.ASCII.GetString(stream.ToArray());
}
}
Found a 'work-around' way to do it.. Instead of putting XMLArray and XMLArrayList attributes above the List<>:
[XmlRoot ("someConfiguration")]
public class SomeConfiguration
{
[XmlArray("bugs")]
[XmlArrayItem("bug")]
public List<string> Bugs { get; set; }
}
Put an XmlElement attribute on the list which will specify the tag to be used for each element and not have a tag wrapping the list. Your class tag will in effect do that for you.
[XmlRoot ("bugs")]
public class SomeConfiguration
{
[XmlElement("bug")]
public List<string> Bugs { get; set; }
}
When you serialize the above, you will end up with:
<bugs>
<bug>Bug1</bug>
<bug>Bug2</bug>
<bug>Bug3</bug>
</bugs>
I have an XML document, and using deserialization, is there a way to combine two elements into one object?
XML example:
<Parameter1>3</Parameter1>
<Parameter2>4</Parameter2>
I want to create a list (of type Parameter) that contains both items, 3 and 4.
I've tried using XmlArrayItem such as:
[XmlArrayItem("Parameter1")]
[XmlArrayItem("Parameter2")]
[XmlArray]
public Parameter[] Parameters; // have also tried this as public List<Parameter> Parameters = new List<Parameter>();
I've tried using XmlElements (but I can't figure out how to combine them):
[XmlElement("Parameter1")]
public List<Parameter> Parameters = new List<Parameter>();
Is there any way to do this without just creating two separate lists and combining them at a later point?
Please note that changing the XML format is not an option.
Your XML has a schema that includes a choice element. A choice element indicates that one of a fixed set of elements -- <Parameter1> and <Parameter2> in your case -- will occur in the XML. XmlSerializer supports choice elements as is explained in Choice Element Binding Support:
If individual choice elements' types differ along with their names, Xsd.exe applies only XmlElementAttribute attributes to a public member. If they differ only by name, Xsd.exe applies an XmlChoiceIdentifierAttribute in addition, and adds extra logic for making the choice.
Thus, you have the following options to deserialize your XML:
Subclass your Parameter class and specify different types for each element name, using [XmlElementAttribute(String, Type)]. The specific Parameter subclass instantiated would thereby capture the XML element name.
I.e. you could do:
public abstract class Parameter
{
[XmlText]
public string Value { get; set; } // Could be int if you prefer.
}
public class Parameter1 : Parameter
{
}
public class Parameter2 : Parameter
{
}
[XmlType("Root")]
public class RootObject
{
[XmlElement("Parameter1", typeof(Parameter1))]
[XmlElement("Parameter2", typeof(Parameter2))]
public Parameter[] Parameters { get; set; }
}
If you want to use the same Parameter type to deserialize both <Parameter1> and <Parameter2> elements, you must introduce an ancillary XmlChoiceIdentifierAttribute array to capture the XML element name:
public class Parameter
{
[XmlText]
public string Value { get; set; }
}
[XmlType("Root")]
public class RootObject
{
[XmlElement("Parameter1", typeof(Parameter))]
[XmlElement("Parameter2", typeof(Parameter))]
[XmlChoiceIdentifier("ParametersElementName")]
public Parameter[] Parameters { get; set; }
[XmlIgnore]
public ParametersChoiceType[] ParametersElementName { get; set; }
}
[XmlType(IncludeInSchema = false)]
public enum ParametersChoiceType
{
Parameter1,
Parameter2,
}
After deserialization, the ParametersElementName array will have the same number of entries as the Parameters array, and the enum values therein will indicate the XML element name actually encountered for each parameter.
As a variation of option 2, if you do not need to capture the XML element name and just want to deserialize the values, you could create a "fake" choice array property as follows:
[XmlType("Root")]
public class RootObject
{
[XmlElement("Parameter1", typeof(Parameter))]
[XmlElement("Parameter2", typeof(Parameter))]
[XmlChoiceIdentifier("ParametersElementName")]
public Parameter[] Parameters { get; set; }
[XmlIgnore]
public ParametersChoiceType[] ParametersElementName
{
get
{
if (Parameters == null)
return null;
return Parameters.Select(p => ParametersChoiceType.Parameter1).ToArray();// Arbitrarily return ItemsChoiceType.Parameter1
}
set
{
// Do nothing - don't care.
}
}
}
XmlSerializer requires you to use one of these two options. If it cannot determine a correct element name by type or by item choice identifier, it will throw an InvalidOperationException with the message:
You need to add XmlChoiceIdentifierAttribute to the 'Parameters' member.
Prototype fiddle showing each option.
What if you do something like this:
//get the xml doc
const string str = #"<root>
<Parameter1>3</Parameter1>
<Parameter2>4</Parameter2>
</root>";
var xml = new XmlDocument();
//load it
xml.LoadXml(str);
//get the nodes where the names contain the string parameter
var xnList = xml.SelectNodes("//*[contains(name(),'Parameter')]");
//create a list of parameters
var list = new List<Parameter>();
//populate the list with the value in the node's innertext
foreach (XmlNode xn in xnList)
{
list.Add(new Parameter{ Value = int.Parse(xn.InnerText) } );
}
foreach(var param in list)
Console.WriteLine(param.Value); //should print 3 and 4
I am using this class as an example:
class Parameter{
public int Value { get; set; }
}
Is is possible to serialize a custom struct as an xml attribute?
Sample code:
public class Dummy<T>
{
private Dummy() { }
public Dummy(T item1)
{
Item1 = item1;
Item2 = item1;
}
public T Item1 { get; set; }
[XmlAttribute]
public T Item2 { get; set; }
}
public struct Meh
{
public int Prop { get; set; }
}
[Test]
public void XmlMehTest()
{
var meh = new Meh{Prop = 1};
var dummy = new Dummy<Meh>(meh);
using (var writer = new StringWriter())
{
var serializer = new XmlSerializer(dummy.GetType());
// System.InvalidOperationException : Cannot serialize member 'Meh2' of type Meh.
// XmlAttribute/XmlText cannot be used to encode complex types.
serializer.Serialize(writer, dummy);
Console.Write(writer.ToString());
}
}
[Test]
public void XmlDateTimeTest()
{
var dummy = new Dummy<DateTime>(DateTime.Now);
using (var writer = new StringWriter())
{
var serializer = new XmlSerializer(dummy.GetType());
serializer.Serialize(writer, dummy);
Console.Write(writer.ToString());
}
}
Please ignore that the struct is mutable, wrote it like that for a compact sample.
This is truly a first-world-developer-problem but I'm still curious :)
The documentation says:
You can assign the XmlAttributeAttribute only to public fields or public properties that return a value (or array of values) that can be mapped to one of the XML Schema definition language (XSD) simple types (including all built-in datatypes derived from the XSD anySimpleType type). The possible types include any that can be mapped to the XSD simple types, including Guid, Char, and enumerations.
So to do this, we should be able to create our own type definition for XSD,I guess we can do that.Because this documentation contains full explanation about it.But what we can't do is, we can't include our definition to this list.Initially XML Serializer uses these types to figure out your type's XSD type definition.You can use this attribute with DateTime because it's definition creating with this method and storing in a HashTable:
AddPrimitive(typeof(DateTime), "dateTime", "DateTime",
TypeFlags.XmlEncodingNotRequired |
TypeFlags.HasCustomFormatter |
TypeFlags.CanBeElementValue | **TypeFlags.CanBeAttributeValue**);
AddPrimitive method:
private static void AddPrimitive(Type type, string dataTypeName, string formatterName, TypeFlags flags)
{
XmlSchemaSimpleType dataType = new XmlSchemaSimpleType {
Name = dataTypeName
};
TypeDesc desc = new TypeDesc(type, true, dataType, formatterName, flags);
if (primitiveTypes[type] == null)
{
primitiveTypes.Add(type, desc);
}
primitiveDataTypes.Add(dataType, desc);
primitiveNames.Add(dataTypeName, "http://www.w3.org/2001/XMLSchema", desc);
}
And this definition calling from XmlReflectionImporter like this (which is generating the exception according to StackTrace):
this.GetTypeDesc(name, ns, TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue | TypeFlags.CanBeAttributeValue);
I guess most important thing is here TypeFlags.CanBeAttributeValue and I think it's specify that this type can be attibute value.So as a result maybe we can serialize custom structs as an XmlAttirube but we can't do it with standart XmlSerializer.Because as I said it's using this list to figure out XSD type definition.And it's an initial list and it's impossible to add new element to that list.
P.S. You might want take a look at here http://msdn.microsoft.com/en-us/library/8w07bk3h(v=vs.80).aspx
I got a XML File, looking familiar to this :
<root>
<carnumber>12</carnumber>
<carcolor>2</carcolor>
<cartype>5</cartype>
</root>
Like you see I got some Elements with values/text in it. The car element for example can take values from 1 to 1000. But the element carcolor can take values from 1 - 5 and the cartype from 1 - 10.
The important thing is that the values of the carcolor and cartype elements mean something. carcolor "2" means red, "1" blue and so on.
So I need to present the user not the values but the real meaning of the values.
I found myself creating some classes that represent the elements with there valid values and things got really complicated and I dont know if this was/is the best way.
A friend of mine suggested me to use XML serialization because my XML file is static. It will never change.
My question is simple. I just wanna know how you would solve this problem. My idea contains classes that represent the XML element, for example cartype within this class I have a Dictonary with a pair. This represent the values within the XML file and the string is the meaning of this value. And I use a lot of Linq to navigate and edit the values.
Thanks again!
This can be as complicated or easy as you want it to be. I would, however, second your friends suggestion to use XML Serialization, something like:
[XmlRoot("Car")]
public class Car
{
public Car()
{
}
[XmlElement("Number")]
public int Number { get; set; }
[XmlElement("Color")]
public int Color { get; set; }
[XmlElement("Type")]
public int Type { get; set; }
}
Serialization:
Car myCar = new Car();
myCar.Number = 1;
myCar.Color = 2;
myCar.Type = 3;
XmlSerializer s = new XmlSerializer(typeof(Car));
TextWriter w = new StreamWriter( #"c:\Car.xml" );
s.Serialize(w, myCar);
w.Close();
Deserialization:
Car myCar;
TextReader r = new StreamReader("Car.xml");
myCar = (Car)s.Deserialize(r);
r.Close();
You could further improve this by exposing a custom enum for the likes of your Type field and internally serializing the number relating to it. Also perhaps exposing the Color enum for the car and internally storing a numerical value.
Give this a try:
[XmlRoot("root")]
public class Car
{
private static XmlSerializer serializer = new XmlSerializer(typeof(Car));
[XmlElement("carnumber")]
public int Number { get; set; }
[XmlElement("carcolor")]
public int Color { get; set; }
[XmlElement("cartype")]
public int Type { get; set; }
[XmlIgnore]
public CarColor CarColor
{
get
{
return (CarColor)Color;
}
set
{
Color = (int)value;
}
}
[XmlIgnore]
public CarType CarType
{
get
{
return (CarType)Type;
}
set
{
Type = (int)value;
}
}
public string CarColorString
{
get
{
return this.CarColor.ToString().Replace('_', ' ');
}
}
public string CarTypeString
{
get
{
return this.CarType.ToString().Replace('_', ' ');
}
}
public string Serialize()
{
StringBuilder sb = new StringBuilder();
using (StringWriter writer = new StringWriter(sb))
{
serializer.Serialize(writer, this);
}
return sb.ToString();
}
public static Car Deserialize(string xml)
{
using (StringReader reader = new StringReader(xml))
{
return (Car)serializer.Deserialize(reader);
}
}
}
public enum CarColor
{
Red = 1,
Blue = 2,
Green = 3,
Light_Brown = 4
// and so on...
}
public enum CarType
{
Sedan = 1,
Coupe = 2,
Hatchback = 3,
SUV = 4,
Pickup_Truck = 5
// and so on...
}
I've added some enums to allow for presentation.
You can set the values of a Car and serialize it to an xml string:
Car car = new Car();
car.Number = 1;
car.CarColor = CarColor.Blue;
car.CarType = CarType.Coupe;
string xml = car.Serialize();
And deserialize an xml string into a car:
string example =
#"<root>
<carnumber>12</carnumber>
<carcolor>2</carcolor>
<cartype>5</cartype>
</root>";
Car car = Car.Deserialize(example);
For presentation, you can use the CarColorString and CarTypeString properties, which, in case your enum values contain more than one word, replace underscores with spaces.
Console.WriteLine(car.CarColorString);
Console.WriteLine(car.CarTypeString);
Why not format your XML file more like:
<root>
<carnumber code="2" name="John's Car"/>
<carcolor code="3" name="Red"/>
<cartype code="2" name="Hatchback"/>
</root>
I would build the UI in WPF, not WinForms. Set up a data context that binds to the XML as an XML data source, write type converters to round trip the data between the internal and human-readable values, bind combo boxes to the various elements, and Bob's your uncle.
I recognize that this answer isn't very useful to you if you're not using WPF.
Suppose I have the following (trivially simple) base class:
public class Simple
{
public string Value { get; set; }
}
I now want to do the following:
public class PathValue : Simple
{
[XmlAttribute("path")]
public string Value { get; set; }
}
public class ObjectValue : Simple
{
[XmlAttribute("object")]
public string Value { get; set; }
}
But without actually redefining the property. I want to apply attributes to members of the base class. Is this possible?
The real problem is that in my serialization mechanism from/to XML (which works brilliantly btw), I find a lot of similar elements where only the names of the attributes differ (they're not consistent, and I don't control the format). Right now I need to create a different class for every such element, whereas they're like 100% the same (apart from the attributes).
I don't think it's possible, but you might never know.
UPDATE:
I tried Marc's approach, but to no avail:
public class Document
{
public PathValue Path;
public ObjectValue Object;
}
class Program
{
static void Main(string[] args)
{
var doc = new Document()
{
Path = new PathValue() { Value = "some path" },
Object = new ObjectValue() { Value = "some object" }
};
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(PathValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("path") });
overrides.Add(typeof(ObjectValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("object") });
XmlSerializer serializer = new XmlSerializer(typeof(Document), overrides);
serializer.Serialize(Console.Out, doc);
Console.WriteLine();
Console.ReadLine();
}
}
...doesn't do the trick.
I'm going to answer this question myself, so that I can accept this answer. I don't like the answer, but I suppose it's the only valid answer.
The answer is: No, you can't do it.
Could you perhaps use the overload XmlSerializer constructor that lets you pass in the attributes to apply at runtime? Then you don't have to worry about it...
caveat: you want to cache the serializer instance and re-use it; otherwise (with the complex constructors) it does dynamic type generation each time.
Example:
using System;
using System.Xml.Serialization;
public class Simple {
public string Value { get; set; }
static void Main() {
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Simple), "Value", new XmlAttributes {
XmlAttribute = new XmlAttributeAttribute("path")
});
XmlSerializer pathSerializer = new XmlSerializer(
typeof(Simple), overrides);
// cache and re-use pathSerializer!!!
Simple obj = new Simple();
obj.Value = "abc";
pathSerializer.Serialize(Console.Out, obj);
}
}
Output:
<Simple xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" path="abc" />
How about this:
public class Simple
{
[XmlIgnore]
public string Value { get; set; }
}
public class PathValue : Simple
{
[XmlAttribute("path")]
public string Path {
get { return base.Value != null ? base.Value : null; }
set { base.Value = value != null ? value : null; }
}
}
public class ObjectValue : Simple
{
[XmlAttribute("object")]
public string Object {
get { return base.Value != null ? base.Value : null; }
set { base.Value = value != null ? value : null; }
}
}
This is the same technique used to serialize an unserializable type like a Uri that takes a serializable type in the constructor.
You are probably aware of this, but as an idea (although the code structure would completely change in that case):
One way would be to serialize the base class as a collection of name-value pairs, using custom serialization (there is also XDocument and similar helpful stuff to make it easier). Although it doesn't enforce type safety, it would spare you from doing lots of manual work.
I also prefer going for custom serialization because it allows a wider range of possibilities (serializing immutable classes, for example). XmlSerializer is also really nasty sometimes (e.g. I hate adding the "MyFieldSpecified" property to create optional attributes).
Perhaps you can mark the base class property with a common mapping, than you only override the property in inherited classes where it should be different. At least you would save some overriding.