NDW

アプリ開発やトラブルシューティング等のノウハウ、キャンプや登山の紹介や体験談など。

.NET Core 1. システムエンジニアリング 実装技術

.NET Core(C#): enumで文字列を保持

投稿日:2021年7月18日 更新日:

はじめに

サンプル

カスタムの属性を定義し、列挙体の各値に表示名・文字列値を設定できるるようにするサンプルです。設定した表示値・文字列値は列挙体の拡張メソッドで取得できるようにします。
実際の業務利用では、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"







-.NET Core, 1. システムエンジニアリング, 実装技術

関連記事

wildflyへのwarデプロイの自動化

更新したWebアプリをWildflyにデプロイするのが面倒なのでスクリプトを作成してみました。 前提 実行環境はCentOS Linux 7です。 JavaEEのWebアプリの配布形式であるwarファ …

パック10進数の変換方法とC#のサンプル

なお、ゾーン10進数はこちらで紹介しています。 パック10進数 ゾーン10進数の変換方法 10進数の各桁を「上位4ビットで1桁、下位4ビットで1桁」のバイトに変換して生成します。 生成したバイト列の最 …

開発・検証用のダミーメールサーバの構築(fakeSMTP)

アプリ開発や検証等でメールサーバを利用したい場合がある。 プロジェクトで共有の検証用メールサーバを構築できると効率が良いか、その準備が間に合わなかったり、使用者が限定的な場合は、使用者の開発環境上に構 …

技術検証

LinuxでGoogle Driveを操作(rcloneの使い方)

概要 RHEL8.3にて、rcloneを使用してGoogle Driveに接続する方法を説明します。 rclone.org  1 Tweet 168 Users 3189 PocketsRc …

.NET Core(C#): 配列/List/Dictionary/HashSet変換方法

はじめに 次の環境を使用して動作確認しています。 OS Windows 10(64ビット) IDE Microsoft Visual Studio Community 2019(16.8.5) + C …