I've run into a few gotchas when doing C# XML serialization that I thought I'd share:
- You can't serialize items that are read-only (like KeyValuePairs)
- You can't serialize a generic dictionary. Instead, try this wrapper class (from http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx):
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
TKey key = (TKey)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
TValue value = (TValue)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
this.Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
foreach (TKey key in this.Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
TValue value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
}
Any other XML Serialization gotchas out there?
If you try to serialize an array,
List<T>
, orIEnumerable<T>
which contains instances of subclasses ofT
, you need to use the XmlArrayItemAttribute to list all the subtypes being used. Otherwise you will get an unhelpfulSystem.InvalidOperationException
at runtime when you serialize.Here is part of a full example from the documentation
Properties marked with the
Obsolete
attribute aren't serialized. I haven't tested withDeprecated
attribute but I assume it would act the same way.I believe this also gets you if you are exposing the private members through public properties - the private members don't get serialised so the public members are all referencing null values.
Can't serialize an object which doesn't have a parameterless construtor (just got bitten by that one).
And for some reason, from the following properties, Value gets serialised, but not FullName:
I never got round to working out why, I just changed Value to internal...
If the serializer encounters a member/property that has an interface as its type, it won't serialize. For example, the following won't serialize to XML:
Though this will serialize:
One more thing to note: you can't serialize private/protected class members if you are using the "default" XML serialization.
But you can specify custom XML serialization logic implementing IXmlSerializable in your class and serialize any private fields you need/want.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx