web-dev-qa-db-ja.com

Enumの値の属性を取得する

列挙型の属性ではなく、列挙型の値の属性を取得できるかどうかを知りたいですか。たとえば、次のような列挙型があるとします。

using System.ComponentModel; // for DescriptionAttribute

enum FunkyAttributesEnum
{
    [Description("Name With Spaces1")]
    NameWithoutSpaces1,    
    [Description("Name With Spaces2")]
    NameWithoutSpaces2
}

私が欲しいのはenum型を与えられ、enum文字列値とその説明の2タプルを生成します。

値は簡単でした:

Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
    Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);

しかし、Tuple.Descを生成するために、description属性の値を取得するにはどうすればよいですか? Attributeがenum自体に属している場合はどうすればよいかを考えることができますが、enumの値からそれを取得する方法については迷います。

434
Alex K

これはあなたが必要とすることをするべきです。

var type = typeof(FunkyAttributesEnum);
var memInfo = type.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var mem = memInfo.FirstOrDefault(m => m.DeclaringType == type);
var attributes = mem.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[0]).Description;
457
Bryan Rowe

このコードは一般的な属性を取得することを可能にするすべての列挙型に対する素晴らしい小さな拡張メソッドを提供します。私はそれが使用するのがより簡単で、わずかに - あなたがジェネリック型を渡すだけでよいので、それが上のラムダ関数と異なると思います。

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T:System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (attributes.Length > 0) ? (T)attributes[0] : null;
    }
}
249
AdamCrawford

これは、選択にラムダを使った一般的な実装です。

public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
    where T : Attribute
{
    T attribute =
      enumeration
        .GetType()
        .GetMember(enumeration.ToString())
        .Where(member => member.MemberType == MemberTypes.Field)
        .FirstOrDefault()
        .GetCustomAttributes(typeof(T), false)
        .Cast<T>()
        .SingleOrDefault();

    if (attribute == null)
        return default(Expected);

    return expression(attribute);
}

このようにそれを呼ぶ:

string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
79
Scott Belchak

もう少し拡張性の高いソリューションを作成するために、ここでいくつかの答えをマージしました。念のために提供していますが、将来的に他の誰かに役立つ場合があります。元の投稿 はこちら

using System;
using System.ComponentModel;

public static class EnumExtensions {

    // This extension method is broken out so you can use a similar pattern with 
    // other MetaData elements in the future. This is your base method for each.
    public static T GetAttribute<T>(this Enum value) where T : Attribute {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        return attributes.Length > 0 
          ? (T)attributes[0]
          : null;
    }

    // This method creates a specific call to the above method, requesting the
    // Description MetaData attribute.
    public static string ToName(this Enum value) {
        var attribute = value.GetAttribute<DescriptionAttribute>();
        return attribute == null ? value.ToString() : attribute.Description;
    }

}

このソリューションはEnum上で一対の拡張メソッドを作成します。 1つ目は、リフレクションを使用して自分の値に関連付けられている属性を取得することを可能にします。 2番目の呼び出しは、特にDescriptionAttributeを呼び出し、そのDescription値を返します。

例として、System.ComponentModelDescriptionAttribute属性を使用することを検討してください。

using System.ComponentModel;

public enum Days {
    [Description("Sunday")]
    Sun,
    [Description("Monday")]
    Mon,
    [Description("Tuesday")]
    Tue,
    [Description("Wednesday")]
    Wed,
    [Description("Thursday")]
    Thu,
    [Description("Friday")]
    Fri,
    [Description("Saturday")]
    Sat
}

上記の拡張方法を使用するには、ここで単純に次のように呼びます。

Console.WriteLine(Days.Mon.ToName());

または

var day = Days.Mon;
Console.WriteLine(day.ToName());
57
Troy Alford

AdamCrawfordレスポンス に加えて、説明を得るためにそれをフィードするより特殊な拡張メソッドをさらに作成しました。

public static string GetAttributeDescription(this Enum enumValue)
{
    var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
    return attribute == null ? String.Empty : attribute.Description;
} 

それ故、説明を得るために、あなたはオリジナルの拡張方法を使うことができます。

string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description

あるいは、単純にここで拡張メソッドを呼び出すこともできます。

string desc = myEnumVariable.GetAttributeDescription();

うまくいけばあなたのコードをもう少し読みやすくするはずです。

38
FunksMaName

流暢なライナー...

ここではDisplayAttributeプロパティとNameプロパティの両方を含むDescriptionを使用しています。

public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
    return enumType.GetMember(enumValue.ToString())
                   .First()
                   .GetCustomAttribute<DisplayAttribute>();
}

public enum ModesOfTransport
{
    [Display(Name = "Driving",    Description = "Driving a car")]        Land,
    [Display(Name = "Flying",     Description = "Flying on a plane")]    Air,
    [Display(Name = "Sea cruise", Description = "Cruising on a dinghy")] Sea
}

void Main()
{
    ModesOfTransport TransportMode = ModesOfTransport.Sea;
    DisplayAttribute metadata = TransportMode.GetDisplayAttributesFrom(typeof(ModesOfTransport));
    Console.WriteLine("Name: {0} \nDescription: {1}", metadata.Name, metadata.Description);
}

出力

Name: Sea cruise 
Description: Cruising on a dinghy
14
Aydin

これがDisplay属性から情報を取得するためのコードです。一般的な方法を使用して属性を取得します。属性が見つからない場合は、enum値をPascal/camelケースをtitleケースに変換した文字列に変換します(ここで取得したコード)。

public static class EnumHelper
{
    // Get the Name value of the Display attribute if the   
    // enum has one, otherwise use the value converted to title case.  
    public static string GetDisplayName<TEnum>(this TEnum value)
        where TEnum : struct, IConvertible
    {
        var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
        return attr == null ? value.ToString().ToSpacedTitleCase() : attr.Name;
    }

    // Get the ShortName value of the Display attribute if the   
    // enum has one, otherwise use the value converted to title case.  
    public static string GetDisplayShortName<TEnum>(this TEnum value)
        where TEnum : struct, IConvertible
    {
        var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
        return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName;
    }

    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="TEnum">The enum type</typeparam>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="value">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    private static T GetAttributeOfType<TEnum, T>(this TEnum value)
        where TEnum : struct, IConvertible
        where T : Attribute
    {

        return value.GetType()
                    .GetMember(value.ToString())
                    .First()
                    .GetCustomAttributes(false)
                    .OfType<T>()
                    .LastOrDefault();
    }
}

そしてこれはタイトルケースに変換するための文字列の拡張メソッドです:

    /// <summary>
    /// Converts camel case or Pascal case to separate words with title case
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static string ToSpacedTitleCase(this string s)
    {
        //https://stackoverflow.com/a/155486/150342
        CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
        TextInfo textInfo = cultureInfo.TextInfo;
        return textInfo
           .ToTitleCase(Regex.Replace(s, 
                        "([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 "));
    }
7
Colin

Enumから辞書を入手してください。

public static IDictionary<string, int> ToDictionary(this Type enumType)
{
    return Enum.GetValues(enumType)
    .Cast<object>()
    .ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k); 
}

今すぐこれを呼び出す...

var dic = typeof(ActivityType).ToDictionary();

EnumDecription Extメソッド

public static string ToEnumDescription(this Enum en) //ext method
{
    Type type = en.GetType();
    MemberInfo[] memInfo = type.GetMember(en.ToString());
    if (memInfo != null && memInfo.Length > 0)
    {
        object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attrs != null && attrs.Length > 0)
            return ((DescriptionAttribute)attrs[0]).Description;
    }
    return en.ToString();
}

public enum ActivityType
{
    [Description("Drip Plan Email")]
    DripPlanEmail = 1,
    [Description("Modification")]
    Modification = 2,
    [Description("View")]
    View = 3,
    [Description("E-Alert Sent")]
    EAlertSent = 4,
    [Description("E-Alert View")]
    EAlertView = 5
}
4

列挙型の値から説明を取得するためにこの拡張メソッドを実装しました。それはあらゆる種類の列挙型に有効です。

public static class EnumExtension
{
    public static string ToDescription(this System.Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());
        var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }
}
3
Nick N.

これは、 System.Reflection.TypeExtensions を使用した、AdamCrawfordの答えの.NET Coreバージョンです。

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        IEnumerable<Attribute> attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (T)attributes?.ToArray()[0];
    }
}
3
wonea

Net FrameworkとNetCoreに私のソリューションを追加する。

私はこれを私のNet Frameworkの実装に使いました。

public static class EnumerationExtension
{
    public static string Description( this Enum value )
    {
        // get attributes  
        var field = value.GetType().GetField( value.ToString() );
        var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false );

        // return description
        return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found";
    }
}

これはNetCoreでは機能しないので、これを行うように修正しました。

public static class EnumerationExtension
{
    public static string Description( this Enum value )
    {
        // get attributes  
        var field = value.GetType().GetField( value.ToString() );
        var attributes = field.GetCustomAttributes( false );

        // Description is in a hidden Attribute class called DisplayAttribute
        // Not to be confused with DisplayNameAttribute
        dynamic displayAttribute = null;

        if (attributes.Any())
        {
            displayAttribute = attributes.ElementAt( 0 );
        }

        // return description
        return displayAttribute?.Description ?? "Description Not Found";
    }
}

列挙例:

public enum ExportTypes
{
    [Display( Name = "csv", Description = "text/csv" )]
    CSV = 0
}

追加されたいずれかの静的の使用例

var myDescription = myEnum.Description();
3
HouseCat

いくつかの新しいC#言語機能を利用すると、行数を減らすことができます。

public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumVal) where TAttribute : Attribute
{
    var memberInfo = enumVal.GetType().GetMember(enumVal.ToString());
    return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false).OfType<TAttribute>().FirstOrDefault();
}

public static string GetEnumDescription(this Enum enumValue) => enumValue.GetEnumAttribute<DescriptionAttribute>()?.Description ?? enumValue.ToString();
2
Rob Lyndon

この答えはenum属性からコンボボックスを設定するための素晴らしいものでした。

それから、ボックスから選択を取得して正しい型で列挙を返すことができるように、逆をコーディングする必要がありました。

私はまた、属性が欠けているケースを処理するためにコードを修正しました

次の人の利益のために、これが私の最後の解決策です

public static class Program
{
   static void Main(string[] args)
    {
       // display the description attribute from the enum
       foreach (Colour type in (Colour[])Enum.GetValues(typeof(Colour)))
       {
            Console.WriteLine(EnumExtensions.ToName(type));
       }

       // Get the array from the description
       string xStr = "Yellow";
       Colour thisColour = EnumExtensions.FromName<Colour>(xStr);

       Console.ReadLine();
    }

   public enum Colour
   {
       [Description("Colour Red")]
       Red = 0,

       [Description("Colour Green")]
       Green = 1,

       [Description("Colour Blue")]
       Blue = 2,

       Yellow = 3
   }
}

public static class EnumExtensions
{

    // This extension method is broken out so you can use a similar pattern with 
    // other MetaData elements in the future. This is your base method for each.
    public static T GetAttribute<T>(this Enum value) where T : Attribute
    {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);

        // check if no attributes have been specified.
        if (((Array)attributes).Length > 0)
        {
            return (T)attributes[0];
        }
        else
        {
            return null;
        }
    }

    // This method creates a specific call to the above method, requesting the
    // Description MetaData attribute.
    public static string ToName(this Enum value)
    {
        var attribute = value.GetAttribute<DescriptionAttribute>();
        return attribute == null ? value.ToString() : attribute.Description;
    }

    /// <summary>
    /// Find the enum from the description attribute.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="desc"></param>
    /// <returns></returns>
    public static T FromName<T>(this string desc) where T : struct
    {
        string attr;
        Boolean found = false;
        T result = (T)Enum.GetValues(typeof(T)).GetValue(0);

        foreach (object enumVal in Enum.GetValues(typeof(T)))
        {
            attr = ((Enum)enumVal).ToName();

            if (attr == desc)
            {
                result = (T)enumVal;
                found = true;
                break;
            }
        }

        if (!found)
        {
            throw new Exception();
        }

        return result;
    }
}

}

2
Steve Pinfold

この拡張メソッドは、そのXmlEnumAttributeを使用して列挙値の文字列表現を取得します。 XmlEnumAttributeが存在しない場合は、enum.ToString()にフォールバックします。

public static string ToStringUsingXmlEnumAttribute<T>(this T enumValue)
    where T: struct, IConvertible
{
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("T must be an enumerated type");
    }

    string name;

    var type = typeof(T);

    var memInfo = type.GetMember(enumValue.ToString());

    if (memInfo.Length == 1)
    {
        var attributes = memInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);

        if (attributes.Length == 1)
        {
            name = ((System.Xml.Serialization.XmlEnumAttribute)attributes[0]).Name;
        }
        else
        {
            name = enumValue.ToString();
        }
    }
    else
    {
        name = enumValue.ToString();
    }

    return name;
}
1
saille

あなたのenumEqualsのような値を含んでいるなら、ここで多くの答えの中でいくつかの拡張を使っていくつかのバグにぶつかるかもしれません。これは通常、typeof(YourEnum).GetMember(YourEnum.Value)が1つの値のみを返すと想定されているからです。それはあなたのMemberInfoenumです。これは少し安全なバージョンです Adam Crawfordの答え

public static class AttributeExtensions
{
    #region Methods

    public static T GetAttribute<T>(this Enum enumValue) where T : Attribute
    {
        var type = enumValue.GetType();
        var memberInfo = type.GetMember(enumValue.ToString());
        var member = memberInfo.FirstOrDefault(m => m.DeclaringType == type);
        var attribute = Attribute.GetCustomAttribute(member, typeof(T), false);
        return attribute is T ? (T)attribute : null;
    }

    #endregion
}
1
Prince Owen

そして、あなたが名前の完全なリストが欲しいなら、あなたは以下のようなことをすることができます

typeof (PharmacyConfigurationKeys).GetFields()
        .Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
        .Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
1
MeTitus

それが私の解決策を共有するのを助けるならみんな:カスタム属性の定義:

    [AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
public class EnumDisplayName : Attribute
{
    public string Name { get; private set; }
    public EnumDisplayName(string name)
    {
        Name = name;
    }
}

HtmlHelperエクステンションのHtmlHelper定義の中でそれを必要としたからです。

public static class EnumHelper
{
    public static string EnumDisplayName(this HtmlHelper helper,EPriceType priceType)
    {
        //Get every fields from enum
        var fields = priceType.GetType().GetFields();
        //Foreach field skipping 1`st fieldw which keeps currently sellected value
        for (int i = 0; i < fields.Length;i++ )
        {
            //find field with same int value
            if ((int)fields[i].GetValue(priceType) == (int)priceType)
            {
                //get attributes of found field
                var attributes = fields[i].GetCustomAttributes(false);
                if (attributes.Length > 0)
                {
                    //return name of found attribute
                    var retAttr = (EnumDisplayName)attributes[0];
                    return retAttr.Name;
                }
            }
        }
        //throw Error if not found
        throw new Exception("Błąd podczas ustalania atrybutów dla typu ceny allegro");
    }
}

それが役に立てば幸い

0
g0rski
    public enum DataFilters
    {
        [Display(Name= "Equals")]
        Equals = 1,// Display Name and Enum Name are same 
        [Display(Name= "Does Not Equal")]
        DoesNotEqual = 2, // Display Name and Enum Name are different             
    }

これで、この場合1 "等しい"というエラーが発生します。

public static string GetDisplayName(this Enum enumValue)
    {
        var enumMember = enumValue.GetType().GetMember(enumValue.ToString()).First();
        return enumMember.GetCustomAttribute<DisplayAttribute>() != null ? enumMember.GetCustomAttribute<DisplayAttribute>().Name : enumMember.Name;
    }

そのため、displaynameとenum nameが同じ場合は、enumMember.GetCustomAttribute()がnullになるため、表示名ではなく列挙名が返される場合.

0
Mohit Dhawan