はじめに
C#のSystem.Xml.Serialization.XmlSerializer
を使って列挙型のシリアライズを行うと,識別子の名前がそのまま出力されてしまっていい感じ(?)ではありません。
そこで,列挙型をシリアライズしたときに出力される文字列をカスタマイズできるようにしてみました。
コード
using System;
using System.Reflection;
using System.Xml.Serialization;
namespace Qiita
{
// 列挙体に任意の文字列を割り当てるための属性
public class CustomTextAttribute : Attrubute
{
public string StringValue { get; protected set; }
public CustomTextAttribute(string value)
{
this.StringValue = value;
}
}
// 列挙体
public enum Wochentage
{
[CustomText("mo")]
Montag,
[CustomText("di")]
Dienstag,
[CustomText("mi")]
Mittwoch,
[CustomText("do")]
Donnerstag,
[CustomText("fr")]
Freitag,
[CustomText("sa")]
Samstag,
[CustomText("so")]
Sonntag
}
// シリアライズのためのラッパー
[Serializable]
public class EnumWrapper<T> where T : Enum
{
protected T value;
[XmlText]
public string Value
{
get
{
// リフレクションで属性を取得
var type = this.value.GetType();
var fieldInfo = type.GetField(this.value.ToString());
if (fieldInfo == null) return this.value.ToString();
var attrs = fieldInfo.GetCustomAttributes<CustomTextAttribute>() as CustomTextAttribute[];
return attrs.Length > 0 ? attrs[0].StringValue : this.value.ToString();
} // get
set
{
// 効率的な方法がわからなかったので強引に頑張る
foreach (T val in Enum.GetValues(typeof(T)))
{
if (val.ToString<CustomTextAttribute>() == value)
this.value = val;
return;
}
} // set
}
public EnumWrapper() { }
public EnumWrapper(T val)
{
this.value = val;
}
// 列挙体との暗黙の型変換を定義
public static implicit operator EnumWrapper<T>(T val)
=> new EnumWrapper<T>(val);
public static implicit operator T(EnumWrapper<T> val)
=> val.value;
} // public class EnumWrapper<T> where T : Enum
} // namespace Qiita
使い方
シリアライズする型の中の列挙体(Wochentage
とします)の型をEnumWrapper<Wochentage>
に変更するだけで,CustomText
属性で指定した値を使用してシリアライズされるようになります。
変更前の型(Wochentage
)と暗黙的に変換できるため,その他のコードに変更を加える必要はありません。
その他
今回はプロパティの中でゴリゴリ書きましたが,CustomTextAttribute
に相当するようなクラスを複数作り,拡張メソッドToString<T>
を定義してあげて文字列に変換する,と言ったこともできます(UIに表示する用とか)。