scrap book

( ..)φメモメモ

(C#)Enumからstringへの変換

よくあるEnumからstringへの変換。世の中に大量に公開されている正解をツギハギして自分にちょうどいいものを探ってみた。
属性定義と拡張メソッドが必要だった。属性定義はDisplayNameAttributeがEnumメンバに付与できないので必要で、拡張メソッドは簡単にアクセスするために必要。DisplayName派生の方が無難だけど参考URL1つ目の思想も好きなので混ざっている。。

ソースコード

using System;
using System.Linq;

namespace EnumToString
{
    // 独自Attribute
    [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
    public sealed class AliasNameAttribute : Attribute
    {
        public string AliasName { get; private set; }

        public AliasNameAttribute(string aliasName)
        {
            AliasName = aliasName;
        }
    }

    // 独自Attribute用のEnum拡張
    public static partial class EnumExtension
    {
        // どうしてもメソッドチェインを崩したくない人用
        public static T ThrowIf<T>(this T value, Func<T, bool> predicate, Exception exception)
        {
            if (predicate(value)) throw exception;
            else return value;
        }

        // AliasNameAttribute.AliasNameを返す。定義されていなければ例外を発生させる。
        public static string ToAliasName(this Enum value)
        {
            return value.GetType()
                .GetField(value.ToString())
                .GetCustomAttributes(typeof(AliasNameAttribute), false)
                .Cast<AliasNameAttribute>()
                .FirstOrDefault()
                .ThrowIf(a => a == null, new ArgumentException("属性が設定されていません。"))
                .AliasName;
        }
    }


    // DisplayName継承Attribute
    //   System.ComponentModel.DisplayNameAttributeと衝突する(こちらへ置換可能)
    [AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
    public class DisplayNameAttribute : System.ComponentModel.DisplayNameAttribute
    {
        public DisplayNameAttribute(string displayName) : base(displayName)
        {
        }
    }

    // DisplayName継承Attribute用のEnum拡張
    public static partial class EnumExtension
    {
        // DisplayNameAttribute.DisplayNameを返す。定義されていなければ定義名を返す。
        public static string ToDisplayName(this Enum value)
        {
            var attribute =
                value.GetType()
                .GetField(value.ToString())
                .GetCustomAttributes(typeof(DisplayNameAttribute), false)
                .Cast<DisplayNameAttribute>()
                .FirstOrDefault();
            return (attribute != null) ? attribute.DisplayName : value.ToString();
        }
    }


    // enum
    enum Fruit
    {
        [AliasName("ブドウ")]
        Grape,
        [DisplayName("あっぷる")]
        [AliasName("リンゴ")]
        Apple,
        [DisplayName("おれんじ")]
        [AliasName("オレンジ")]
        Orange,

        // 属性なし
        Dummy,
    }


    class Program
    {
        static void Main(string[] args)
        {
            // AliasName属性を使用して全要素を表示
            foreach (Fruit f in Enum.GetValues(typeof(Fruit)))
            {
                try
                {
                    Console.WriteLine(f.ToString());
                    Console.WriteLine($"  {f.ToAliasName()}");
                }
                catch (Exception e)
                {
                    Console.WriteLine($"  exception : {e.ToString()}");
                }
            }
            Console.WriteLine();


            // DisplayName属性を使用して全要素を表示
            Console.WriteLine("================");
            foreach (Fruit f in Enum.GetValues(typeof(Fruit)))
            {
                try
                {
                    Console.WriteLine(f.ToString());
                    Console.WriteLine($"  {f.ToDisplayName()}");
                }
                catch (Exception e)
                {
                    Console.WriteLine($"  exception : {e.ToString()}");
                }
            }
            Console.WriteLine();


            // wait for key
            Console.ReadKey();
        }
    }
}

結果

Grape
  ブドウ
Apple
  リンゴ
Orange
  オレンジ
Dummy
  exception : System.ArgumentException: 属性が設定されていません。
   場所 EnumToString.EnumExtension.ThrowIf[T](T value, Func`2 predicate, Exception exception) 場所 ***\Program.cs:行 64
   場所 EnumToString.EnumExtension.ToAliasName(Enum value) 場所 ***\Program.cs:行 71
   場所 EnumToString.Program.Main(String[] args) 場所 ***\Program.cs:行 107

================
Grape
  Grape
Apple
  あっぷる
Orange
  おれんじ
Dummy
  Dummy