Некоторые классы .NET Framework ведут себя при сериализации с помощью XmlSerializer достаточно странно. Некоторые не сериализуются вообще, некоторые, например тот же System.Drawing.Color, сериализуют только поле, но игнорируют его значение. То есть, сериализация объекта со свойством:
[XmlElement("backgroundColor")]
public Color BgColor
{
get { return _bgColor; }
set { _bgColor = value; }
}
приведет к тому, что будет сериализована пустая нода <backgroundColor />, значение же сериализоваться не будет, как бы мы его не присваивали.
К слову, этого я вообще не понимаю. Ну не умеешь ты сериализовать класс - ну выкинь ты исключение, зачем такую ерунду делать... Впрочем, если же возникнет желание сериализовать цвет xml-атрибутом, то, действительно, получится исключение.
Но не об этом речь.
Иногда все же нужно сериализовать несериализуемое, а делать для этого в классах дополнительные свойства, которые будут использоваться только для сериализации (например, можно было бы сделать string StringBgColor, пометить его как Browsable(false), чтобы его никто не видел, а само свойство Color BgColor поменить как XmlIgnore).
Но этот подход мне не нравится, так как в интерфейсе объекта плодятся ненужные свойства, которые, в общем-то, логически дублируют друг друга.
На мой взгляд грамотнее написать свой тип Color точнее, "обертку" для него (назовем ее XmlColor), которая с одной стороны будет нормально сериализоваться, с другой стороны будет "прозрачной" для использования совместно со "стандартным" Color.
То есть, чтобы можно было написать Color myColor = myXmlColor и наоборот, а приведение типов производилось бы автоматически. Тогда введение нового типа никак не будет мешать ни логике работы программы, ни разработчикам.
Вот пример такого типа:
public struct XmlColor : System.Xml.Serialization.IXmlSerializable
{
private Color _color;
public XmlColor(Color c)
{
_color = c;
}
public Color Color
{
get { return _color; }
}
public static implicit operator Color(XmlColor c)
{
return c.Color;
}
public static implicit operator XmlColor(Color c)
{
return new XmlColor(c);
}
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
{
_color = ColorTranslator.FromHtml(reader.ReadString());
}
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteString(ColorTranslator.ToHtml(this.Color));
}
}
Он инкапсулирует в себе "нормальный" Color, "умеет" приводиться к нему и из него, а так же может быть сериализован в качестве xml-элемента. Естественно, вместе со значением :) Таким образом, вместо свойства Color BgColor {get; set;} мы сможем определить свойство XmlColor BgColor {get; set;} и все будет работать так, как планировалось, а благодаря возможности неявного приведения замена одного типа другим пройдет незаметно и безболезненно.
P.S. К слову сказать, реализация IXmlSerializable может быть полезна и в некоторых других случаях. Например, если свойства класса хранят некоторую информацию, которая должна быть доступна в этих свойствах в момент работы приложения, но должна быть сериализована в зашифрованном виде...