1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【C#】enumのシリアライズをカッコよくしたい!

Posted at

はじめに

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に表示する用とか)。

参考文献

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?