Font / Color のXMLシリアライズ

先の例を拡張し,投稿メッセージのフォント(System.Drawing.Font)や色(System.Drawing.Color)もシリアライズしようとすることを考える.
単純に,Contributionクラスに以下の2つのフィールドを追加する.(コンストラクタ等も修正する)


public Font msgFont; //投稿メッセージフォント
public Color msgColor; //投稿メッセージ色

これらを前項と同様にXMLシリアライズしようとすると

System.InvalidOperationException: System.Drawing.Font に既定のパブリック コンストラクタが含まれていないため、シリアル化できません。

なんて例外が発生する.

調べてみたところ,どうやら System.Drawing.Font や System.Drawing.Colorをそのままシリアライズすることはできないらしい.
対策は,System.Drawing.FontConverter / System.Drawing.ColorConverter を使って,Font / Color オブジェクトをstring文字列に変換してからオブジェクトに格納するという方法がある模様.
一番手っ取り早いのは,フィールドでは全部stringにしておいて,呼ぶ側でいちいちstringに変換して格納する.
例えば,Contributionクラスのフィールドを


public string msgFont; //投稿メッセージフォント
public string msgColor; //投稿メッセージ色

にして,シリアライズ部で


using System.IO;
using System.Drawing;
using System.Xml.Serialization;

(略)

// XMLファイルにシリアライズ
string contributionLog = "log.txt";
FontConverter fc = new FontConverter();
Font msgFont = fontDialog.Font; //フォント選択ダイアログで指定したフォント
ColorConverter cc = new ColorConverter();
Color msgColor = fontDialog.Color; //フォント選択ダイアログで指定した色
Contribution contribution = new Contribution(user, "テスト", 3, fc.ConvertToString(msgFont), cc.ConvertToString(msgColor));
XmlSerializer serializer = new XmlSerializer(typeof(Contribution));
FileStream fs = new FileStream(contributionLog, System.IO.FileMode.Create);
serializer.Serialize(fs, contribution);
fs.Close();

としておけば良い.

蛇足

呼び出し側でいちいち,FontConverterやColorConverterでの変換が面倒だからといって,Contributionクラスを以下のようにしても意味がないので注意.


public class Contribution
{
private string msgFont;
private string msgColor;
(中略)
public Font messageFont
{
get
{
FontConverter fc = new FontConverter();
return fc.ConvertFromString(this.msgFont);
}
set
{
FontConverter fc = new FontConverter();
this.msgFont = fc.ConvertToString(value);
}
}

public Color messageColor
{
get
{
ColorConverter cc = new ColorConverter();
return cc.ConvertFromString(this.msgColor);
}
set
{
ColorConverter cc = new ColorConverter();
this.msgColor = cc.ConvertToString(value);
}
}
}

XMLSerializerは,publicプロパティをシリアライズの対象にするので,上記のようにしても,msgFontフィールド(string)ではなく,messageFontプロパティ(Font)に対して,シリアライズを実行しようとして例外が発生してしまう.