Obtenir des attributs de la valeur D'Enum

je voudrais savoir s'il est possible d'obtenir des attributs des valeurs d'enum et pas de l'enum lui-même? Par exemple, supposons que j'ai l'enum suivant:

using System.ComponentModel; // for DescriptionAttribute

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

ce que je veux est donné le type enum, produire 2-tuples de la valeur de chaîne enum et sa description.

valeur était facile:

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

mais comment puis-je obtenir la valeur de l'attribut description, pour peupler Tuple.Desc? Je peux penser à comment le faire si le Attribut appartient à l'enum lui-même, mais je suis à une perte quant à la façon de l'obtenir à partir de la valeur de l'enum.

378
demandé sur Brandon Minnick 2009-11-25 22:23:22

19 réponses

cela devrait faire ce dont vous avez besoin.

var type = typeof(FunkyAttributesEnum);
var memInfo = type.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[0]).Description;
415
répondu Bryan Rowe 2017-02-20 15:51:53

ce morceau de code devrait vous donner une belle petite méthode d'extension sur n'importe quel enum qui vous permet de récupérer un attribut Générique. Je crois que c'est différent de la fonction lambda ci - dessus parce que c'est plus simple à utiliser et légèrement-vous n'avez besoin de passer dans le type générique.

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;
    }
}
222
répondu AdamCrawford 2015-05-14 16:35:48

il s'agit d'une implémentation Générique utilisant un lambda pour la sélection

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);
}

appelez ça comme ça:

string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
75
répondu Scott Belchak 2018-04-28 10:55:03

j'ai fusionné quelques-unes des réponses ici pour créer une solution un peu plus extensible. Je suis fournissant juste au cas où c'est utile à quelqu'un d'autre dans l'avenir. Message d'origine ici .

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 (T)attributes[0];
    }

    // 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;
    }

}

Cette solution crée une paire de méthodes d'extension sur Enum. La première vous permet d'utiliser la réflexion pour récupérer tout attribut associé à votre valeur. Le second appelle spécifiquement "retrieve the 151940920" et renvoie Description de la valeur.

à titre d'exemple, envisagez d'utiliser l'attribut DescriptionAttribute de System.ComponentModel

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
}

pour utiliser la méthode d'extension ci-dessus, vous pouvez maintenant simplement appeler ce qui suit:

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

ou

var day = Days.Mon;
Console.WriteLine(day.ToName());
45
répondu Troy Alford 2017-05-23 12:10:48

En plus de AdamCrawford réponse , j'ai créé des méthodes d'extension d'alimentation pour obtenir la description.

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

par conséquent, pour obtenir la description, Vous pouvez utiliser la méthode d'extension originale comme

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

ou vous pouvez simplement appeler la méthode d'extension ici:

string desc = myEnumVariable.GetAttributeDescription();

qui devrait rendre votre code un peu plus lisible.

37
répondu FunksMaName 2017-05-23 12:10:48

une doublure fluente...

J'utilise ici le DisplayAttribute qui contient à la fois les propriétés Name et Description .

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

exemple

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);
}

Sortie

Name: Sea cruise 
Description: Cruising on a dinghy
10
répondu Aydin Adn 2014-08-03 21:48:33

voici le code pour obtenir des informations à partir d'un attribut Display. Il utilise une méthode générique pour récupérer l'attribut. Si l'attribut n'est pas trouvé, il convertit la valeur enum en une chaîne avec le cas pascal / camel converti en cas de titre (code obtenu ici )

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();
    }
}

et c'est la méthode d'extension pour les chaînes pour convertir au cas du titre:

    /// <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]))", " "));
    }
7
répondu Colin 2017-05-23 12:18:24

obtenir le dictionnaire de enum.

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

appelez ça comme ça...

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

Méthode De Dénombrement

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
répondu Jitendra Pancholi 2014-07-01 12:54:36

j'ai implémenté cette méthode d'extension pour obtenir la description à partir des valeurs enum. Il fonctionne pour tous les types d'énumérations.

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
répondu Nick N. 2013-05-21 14:32:47

Voici la version .net Core de la réponse D'AdamCrawford, en utilisant le système .Réflexion.Extensions ;

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
répondu wonea 2016-12-26 14:25:16

ajout de ma solution pour NET Framework et NetCore.

j'ai utilisé ceci pour mon NET Framework implementation:

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";
    }
}

cela ne fonctionne pas pour NetCore donc je l'ai modifié pour faire ceci:

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";
    }
}

Exemple D'Énumération:

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

exemple d'utilisation pour l'un ou l'autre des éléments statiques ajouté:

var myDescription = myEnum.Description();
3
répondu HouseCat 2017-01-05 16:49:12

en profitant de certaines des nouvelles fonctionnalités du langage C#, vous pouvez réduire le nombre de lignes:

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
répondu Rob Lyndon 2016-10-19 11:23:56

cette méthode d'extension obtiendra une représentation string d'une valeur enum en utilisant sa attribut Xmlenumat. Si aucun XmlEnumAttribute n'est présent, il retombe à 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
répondu saille 2013-08-08 04:04:29

Et si vous voulez la liste complète des noms vous pouvez faire quelque chose comme

typeof (PharmacyConfigurationKeys).GetFields()
        .Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
        .Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
1
répondu Marco 2016-07-05 12:56:34

j'ai cette réponse à l'installation d'une boîte déroulante à partir d'une énumération des attributs qui était super.

j'ai alors eu besoin de coder l'inverse pour que je puisse obtenir la sélection de la boîte et retourner l'enum dans le type correct.

j'ai aussi modifié le code pour gérer le cas où un attribut était manquant

pour les avantages de la prochaine personne, voici ma solution finale

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;
    }
}

}

1
répondu Steve Pinfold 2016-10-19 11:24:35

alternativement, vous pouvez faire ce qui suit:

Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
    {
      { FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
      { FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
    };

et obtenir la description avec la suivante:

string s = description[FunkyAttributesEnum.NameWithoutSpaces1];

À mon avis, c'est une façon plus efficace de faire ce que vous voulez accomplir, pas de réflexion est nécessaire..

0
répondu Ian P 2009-11-25 19:37:28

les gars, si ça peut aider, je partagerai avec vous ma solution: Définition de L'attribut personnalisé:

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

maintenant parce que j'en avais besoin à l'intérieur de HtmlHelper définition de L'Extension 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");
    }
}

j'Espère que ça aide

0
répondu g0rski 2013-12-29 11:23:47
    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             
    }

maintenant, il va produire une erreur dans ce cas 1 "égale"

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;
    }

donc si c'est le même nom enum de retour plutôt que le nom d'affichage parce que enumMember.GetCustomAttribute() obtient null si displayname et enum nom sont les mêmes.....

0
répondu Mohit Dhawan 2018-05-04 10:32:36

vous pouvez également définir une valeur enum comme Name_Without_Spaces , et quand vous voulez une description utiliser Name_Without_Spaces.ToString().Replace('_', ' ') pour remplacer les soulignements par des espaces.

-4
répondu Coda 2013-06-08 23:08:15