はじめに
リンク
サンプル
カスタムの属性を定義し、列挙体の各値に表示名・文字列値を設定できるるようにするサンプルです。設定した表示値・文字列値は列挙体の拡張メソッドで取得できるようにします。
実際の業務利用では、Excel等で表示名や文字列値を含むコード一覧を定義し、Excelマクロで属性値を付与した列挙体のソースコードを出力するような使い方になると考えています。
列挙体への付加情報の定義
EnumInfo属性(EnumInfoAttribute)を定義し、列挙体値の表示名・文字列値を指定できるようにします。
// 列挙体の例1
public enum EnumExTest1{
[EnumInfo("値1", "01")]
Val1,
[EnumInfo("値2", "02")]
Val2,
[EnumInfo("値3", "03")]
Val3
}
// 列挙体の例2
public enum EnumExTest2
{
[EnumInfo("いいえ", "0")]
No,
[EnumInfo("はい", "1")]
Yes
}
/// <summary>
/// 列挙体付加情報属性
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class EnumInfoAttribute : Attribute
{
public string DisplayName { get; }
public string Value { get; }
public EnumInfoAttribute(string displayName, string value)
{
DisplayName = displayName;
Value = value;
}
};Enum拡張メソッドの定義
各列挙体値に設定された表示名・文字列をディクショナリにキャッシュし、列挙体の拡張メソッドで取得できるようにします。
public static class EnumExtensions
{
/// <summary>
/// 表示名ディクショナリ
/// </summary>
private static Dictionary<Enum, string> _displayNameDic =
new Dictionary<Enum, string>();
/// <summary>
/// 文字列値ディクショナリ
/// </summary>
private static Dictionary<Enum, string> _strValDic =
new Dictionary<Enum, string>();
// 使用時の性能向上のため、クラスロード時に纏めて初期化する。
static EnumExtensions()
{
// アセンブリに含まれる列挙体の全てを取得
Assembly assembly = typeof(EnumExtensions).Assembly;
var enumTypes = assembly.GetTypes().Where(e => e.IsEnum).ToArray();
// 列挙体で属性指定がある場合、表示名と文字列値をキャッシュ
foreach (var type in enumTypes)
{
// 列挙体に含まれる全ての値を取得(列挙体の値自身もEnum型)
// (System.Arrayから配列に変換)
var vals = Enum.GetValues(type).OfType<Enum>().ToArray();
// 属性が指定された値がある場合、表示名と文字列値を追加
foreach (var v in vals)
{
var mi = type.GetMember(v.ToString()).FirstOrDefault();
var attr = mi?.GetCustomAttribute<EnumInfoAttribute>();
if (attr != null)
{
_displayNameDic[v] = attr.DisplayName;
_strValDic[v] = attr.Value;
}
}
}
}
/// <summary>
/// 表示名を取得する。
/// </summary>
/// <param name="e">列挙体値</param>
/// <returns>表示名</returns>
public static string GetDisplayName(this Enum e)
=> _displayNameDic.ContainsKey(e) ? _displayNameDic[e]: null;
/// <summary>
/// 文字列値を取得する。
/// </summary>
/// <param name="e">列挙体値</param>
/// <returns>文字列値</returns>
public static string GetStrValue(this Enum e)
=> _strValDic.ContainsKey(e) ? _strValDic[e] : null;
}- 静的コンストラクタを使用して、EnumExtensionExampleクラスロード時に纏めて表示名・文字列値をディクショナリにキャッシュしています。
- 表示名・文字列値の取得が実行された際に属性値からそれぞれの値を取得する方法も考えられますが、都度属性値を取得するより、ディクショナリにキャッシュした値を取得した方が性能が良いだろう、という考えに基づいています。
- Assembly.GetTypes()を使用してこのサンプル(アセンブリ)に含まれる全ての列挙体を取得しています。
- キャッシュに使用しているDictionary<,>は書込みを行わなければスレッドセーフです。詳細はリファレンスをご覧ください。
動作確認
Console.WriteLine(EnumExTest1.Val1.ToString()); // "Val1"
Console.WriteLine((int)EnumExTest1.Val1); // "0"
Console.WriteLine(EnumExTest1.Val1.GetDisplayName()); // "値1"
Console.WriteLine(EnumExTest1.Val1.GetStrValue()); // "01"
Console.WriteLine(EnumExTest2.Yes.ToString()); // "Yes"
Console.WriteLine((int)EnumExTest2.Yes); // "1"
Console.WriteLine(EnumExTest2.Yes.GetDisplayName()); // "はい"
Console.WriteLine(EnumExTest2.Yes.GetStrValue()); // "1"リンク