Obtenir des attributs de la valeur d'Enum

483

Je voudrais savoir s'il est possible d'obtenir des attributs des enumvaleurs et non du enumsoi? Par exemple, supposons que j'ai les éléments suivants enum:

using System.ComponentModel; // for DescriptionAttribute

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

Ce que je veux, c'est le type enum, produire 2-tuples de la valeur de la chaîne enum et sa description.

La 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 de description, pour remplir Tuple.Desc? Je peux penser à la façon de le faire si l'attribut appartient à enumlui - même, mais je ne sais pas comment l'obtenir de la valeur de la enum.

Alex K
la source
À partir d'une autre question stackoverflow.com/questions/469287/…
finnw
2
l'espace de noms requis pour la description est System.ComponentModel
John M
Vous pouvez également simplement ne pas utiliser System.ComponentModel et simplement utiliser votre propre type d'attribut; il n'y a vraiment rien de si spécial DescriptionAttribute.
2018
veuillez voir ce lien: stackoverflow.com/a/58954215/5576498
AminGolmahalle

Réponses:

482

Cela devrait faire ce dont vous avez besoin.

var enumType = typeof(FunkyAttributesEnum);
var memberInfos = enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == enumType);
var valueAttributes = 
      enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)valueAttributes[0]).Description;
Bryan Rowe
la source
10
Utilisez facultativement type.GetFields (BindingFlags.Public | BindingFlags.Static) pour obtenir tous les memInfos à la fois.
TrueWill
4
J'ai dû aller typeof (FunkyAttributesEnum), mais à part ça, cela a bien fonctionné. Merci.
Greg Randall
@AlexK Je ne vois pas la classe Enum a une propriété NameWithoutSpaces1. D'où vient FunkyAttributesEnum.NameWithoutSpaces1?
Don
2
@Don, c'est le nom du membre enum de la question du PO.
MEMark
288

Ce morceau de code devrait vous donner une jolie petite méthode d'extension sur n'importe quelle énumération qui vous permet de récupérer un attribut générique. Je pense que c'est différent de la fonction lambda ci-dessus car elle est plus simple à utiliser et légèrement - il suffit de passer 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><![CDATA[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;
    }
}
AdamCrawford
la source
19
L'utilisation serait alors: string desc = myEnumVariable.GetAttributeOfType <DescriptionAttribute> () .Description;
Brad Rem
2
J'aime plus celui-ci que celui de Scott, car l'utilisation est plus propre ici (moins de frappe), donc +1 :)
nawfal
3
Si aucun attribut n'existe, cela ne lancerait-il pas un IndexOutOfRangeException?
Erik Philips
6
mieux utiliser type.GetMember (Enum.GetName (type, enumVal)) pour le memInfo car enumVal.ToString () peut ne pas être fiable pour différents paramètres régionaux.
Lin Song Yang
2
Quel est l'intérêt d'appeler GetCustomAttributes()puis d'obtenir le premier élément au lieu d'appeler GetCustomAttribute()?
tigrou
81

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 ceci:

string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
Scott Belchak
la source
4
C'est bien. Nous devons juste faire attention si la valeur d'énumération donnée est une combinaison (autorisée par FlagsAttribute). Dans ce cas, enumeration.GetType().GetMember(enumeration.ToString())[0]échouera.
remio
Le plus court que vous puissiez écrire:, value.GetType().GetField(value.ToString()).GetCustomAttributes(false).OfType<T>‌​().SingleOrDefault()mais admettre que votre manière explicite est meilleure.
nawfal
2
J'ajoute également une chaîne publique statique GetDescription (cette énumération Enum) {return enumeration.GetAttributeValue <DescriptionAttribute, String> (x => x.Description); } de cette façon, c'est juste targetLevel.GetDescription ();
MarkKGreenway
65

J'ai fusionné quelques-unes des réponses ici pour créer une solution un peu plus extensible. Je le fournis juste au cas où il serait utile à quelqu'un d'autre à l'avenir. Publication originale 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 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;
    }

}

Cette solution crée une paire de méthodes d'extension sur Enum. Le premier vous permet d'utiliser la réflexion pour récupérer tout attribut associé à votre valeur. Le second appelle spécifiquement récupère le DescriptionAttributeet retourne sa Descriptionvaleur.

Par exemple, envisagez d'utiliser l' DescriptionAttributeattribut deSystem.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 devez maintenant simplement appeler ce qui suit:

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

ou

var day = Days.Mon;
Console.WriteLine(day.ToName());
Troy Alford
la source
Sur la dernière ligne, vous voulez dire "attribut.Description"? attribut de retour == null? value.ToString (): attribute.Description;
Jeson Martajaya
2
J'adore cette solution, mais elle contient un bug. La méthode GetAttribute suppose que la valeur d'énumération a un attribut Description et lève donc une exception lorsque la longueur des attributs est 0. Remplacez les "attributs de retour (T) [0];" avec "return (attributes.Length> 0? (T) attributes [0]: null);"
Simon Gymer
@SimonGymer merci pour la suggestion - j'ai mis à jour en conséquence. :)
Troy Alford
38

En plus de la réponse d'AdamCrawford , j'ai en outre créé des méthodes d'extension plus spécialisées qui s'en nourrissent 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 soit utiliser la méthode d'extension d'origine comme

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

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

string desc = myEnumVariable.GetAttributeDescription();

J'espère que cela devrait rendre votre code un peu plus lisible.

FunksMaName
la source
16

Une doublure fluide ...

Ici, j'utilise le DisplayAttributequi contient à la fois les propriétés Nameet 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);
}

Production

Name: Sea cruise 
Description: Cruising on a dinghy
Aydin
la source
2
J'utilise ça aussi, c'est la plus nette de toutes les réponses! +1
Mafii
Cela semble assez utile! Thnx
Irf
7

Voici le code pour obtenir des informations 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 d'énumération 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 voici la méthode d'extension pour les chaînes à convertir en casse de 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]))", "$1 "));
    }
Colin
la source
4

J'ai implémenté cette méthode d'extension pour obtenir la description des valeurs d'énumération. Cela fonctionne pour toutes sortes 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();
    }
}
Nick N.
la source
une version générique de la même solution est déjà publiée. imo, mieux.
nawfal
4

Obtenez le dictionnaire d'énumération.

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

Maintenant, appelez ça comme ...

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

EnumDecription Ext, méthode

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
}
Jitendra Pancholi
la source
3

Voici la version .NET Core de la réponse d'AdamCrawford, utilisant System.Reflection.TypeExtensions ;

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];
    }
}
wonea
la source
Je ne crois pas que .NET Core (ou plutôt Standard maintenant) dispose de GetMember, donc je ne sais pas comment cela fonctionnerait.
Jeff
C'est dans System.Reflection.TypeExtensions, j'ai révisé ma réponse pour l'énumérer.
wonea
1
Gotcha, merci. J'ai pensé qu'il pourrait y avoir des extensions en jeu.
Jeff
3

Ajout de ma solution pour Net Framework et NetCore.

J'ai utilisé cela pour ma mise en œuvre de 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";
    }
}

Cela ne fonctionne pas pour NetCore, je l'ai donc modifié pour ce faire:

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 statique ajouté:

var myDescription = myEnum.Description();
Un chat domestique
la source
2

Tirant parti 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();
Rob Lyndon
la source
2

J'ai cette réponse pour configurer une zone de liste déroulante à partir d'un attribut enum qui était super.

J'ai ensuite eu besoin de coder l'inverse afin que je puisse obtenir la sélection de la boîte et renvoyer l'énumération dans le bon type.

J'ai également modifié le code pour gérer le cas où un attribut manquait

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

}

Steve Pinfold
la source
1
J'ai vu tant de solutions stupides et inexpliquées, et la tienne l'a tuée. Merci beaucoup <3
Kadaj
2

Si votre enumcontient une valeur telle que Equalsvous pourriez rencontrer quelques bogues en utilisant certaines extensions dans de nombreuses réponses ici. C'est parce qu'il est normalement supposé que typeof(YourEnum).GetMember(YourEnum.Value)ne retournerait qu'une seule valeur, qui est la MemberInfovotre enum. Voici une version légèrement plus sûre de la réponse d'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
}
Prince Owen
la source
1

Cette méthode d'extension obtiendra une représentation sous forme de chaîne d'une valeur d'énumération à l'aide de son XmlEnumAttribute. Si aucun XmlEnumAttribute n'est présent, il revient à 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;
}
saille
la source
1

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);
MeTitus
la source
0

Les gars si ça aide je vais partager 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 dans la définition HtmlHelper 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 cela aide

g0rski
la source
0
    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 produira 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 s'il s'agit du même nom enum de retour plutôt que nom d'affichage car enumMember.GetCustomAttribute () obtient null si le nom d'affichage et le nom d'énumération sont identiques .....

Mohit Dhawan
la source
0

Vous pouvez également effectuer les opérations suivantes:

List<SelectListItem> selectListItems = new List<SelectListItem>();

    foreach (var item in typeof(PaymentTerm).GetEnumValues())
    {
        var type = item.GetType();
        var name = type.GetField(item.ToString()).GetCustomAttributesData().FirstOrDefault()?.NamedArguments.FirstOrDefault().TypedValue.Value.ToString();
        selectListItems.Add(new SelectListItem(name, type.Name));

    }
hodoor
la source
0

C'est ainsi que je l'ai résolu sans utiliser d'aides ou d'extensions personnalisées avec .NET core 3.1.

Classe

public enum YourEnum
{
    [Display(Name = "Suryoye means Arameans")]
    SURYOYE = 0,
    [Display(Name = "Oromoye means Syriacs")]
    OROMOYE = 1,
}

Rasoir

@using Enumerations

foreach (var name in Html.GetEnumSelectList(typeof(YourEnum)))
{
    <h1>@name.Text</h1>
}
Araméen
la source
1
envisagez de répondre à la question en utilisant plus que la façon dont vous l'avez résolu - commencez par reconnaître le problème et expliquez comment vous pensez que cela le résout. N'oubliez pas que votre réponse pourrait être prise hors contexte dans quelques années et qu'elle serait alors presque inutile. Ajouter plus, ajouter du contexte augmenterait votre réponse et sa pertinence historique / archivistique possible
OldFart
0

La performance compte

Si vous voulez de meilleures performances, voici la voie à suivre:

public static class AdvancedEnumExtensions
{
    /// <summary>
    /// Gets the custom attribute <typeparamref name="T"/> for the enum constant, if such a constant is defined and has such an attribute; otherwise null.
    /// </summary>
    public static T GetCustomAttribute<T>(this Enum value) where T : Attribute
    {
        return GetField(value)?.GetCustomAttribute<T>(inherit: false);
    }

    /// <summary>
    /// Gets the FieldInfo for the enum constant, if such a constant is defined; otherwise null.
    /// </summary>
    public static FieldInfo GetField(this Enum value)
    {
        ulong u64 = ToUInt64(value);
        return value
            .GetType()
            .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
            .Where(f => ToUInt64(f.GetRawConstantValue()) == u64)
            .FirstOrDefault();
    }

    /// <summary>
    /// Checks if an enum constant is defined for this enum value
    /// </summary>
    public static bool IsDefined(this Enum value)
    {
        return GetField(value) != null;
    }

    /// <summary>
    /// Converts the enum value to UInt64
    /// </summary>
    public static ulong ToUInt64(this Enum value) => ToUInt64((object)value);

    private static ulong ToUInt64(object value)
    {
        switch (Convert.GetTypeCode(value))
        {
            case TypeCode.SByte:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
                return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture));

            case TypeCode.Byte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Char:
            case TypeCode.Boolean:
                return Convert.ToUInt64(value, CultureInfo.InvariantCulture);

            default: throw new InvalidOperationException("UnknownEnumType");
        }
    }
}

Pourquoi cela a-t-il de meilleures performances?

Parce que les méthodes intégrées utilisent toutes du code très similaire à ceci, sauf qu'elles exécutent également un tas d'autres codes dont nous ne nous soucions pas . Le code Enum de C # est assez horrible en général.

Le code ci-dessus a été Linq-ified et rationalisé afin qu'il ne contienne que les bits qui nous intéressent.

Pourquoi le code intégré est-il lent?

Premièrement concernant Enum.ToString () -vs- Enum.GetName (..)

Utilisez toujours ce dernier. (Ou mieux encore ni l'un ni l'autre, comme cela apparaîtra clairement ci-dessous.)

ToString () utilise ce dernier en interne, mais encore une fois, fait un tas d'autres choses que nous ne voulons pas, par exemple, essaie de combiner des drapeaux, d'imprimer des nombres, etc. Nous ne sommes intéressés que par les constantes définies à l'intérieur de l'énumération.

Enum.GetName obtient à son tour tous les champs, crée un tableau de chaînes pour tous les noms, utilise le ToUInt64 ci-dessus sur tous leurs RawConstantValues ​​pour créer un tableau UInt64 de toutes les valeurs, trie les deux tableaux en fonction de la valeur UInt64 et obtient enfin le nom de le tableau de noms en faisant une recherche binaire dans le tableau UInt64 pour trouver l'index de la valeur que nous voulions.

... puis nous jetons les champs et les tableaux triés utilisent ce nom pour retrouver le champ.

Un mot: "Ugh!"

AnorZaken
la source
-1

Vous pouvez également effectuer les opérations suivantes:

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

Et obtenez la description avec ce qui suit:

string s = description[FunkyAttributesEnum.NameWithoutSpaces1];

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

Ian P
la source
2
Bien sûr, mais la réflexion n'est pas aussi mauvaise que les gens le disent.
Bryan Rowe
Je ne dis pas que c'est mauvais - je l'utilise tout le temps. Cependant, il est souvent utilisé inutilement. :)
Ian P
44
Cette solution éloigne la description de l'énumération elle-même, créant au moins deux gros problèmes. Tout d'abord, si quelqu'un ajoute une nouvelle constante d'énumération, il devra savoir qu'il doit également se rendre à cet autre endroit pour y ajouter une entrée. Les attributs sont un signe clair pour un responsable de ce qu'ils doivent faire. Mon deuxième problème est que c'est juste beaucoup plus de code. Les attributs sont compacts.
scobi
1
@scott mais il vous permet de spécifier votre propre commande et d'exclure les valeurs que vous ne voulez pas afficher, ce qui est presque toujours ce que je veux réellement
Simon_Weaver
-2

Vous pouvez également définir une valeur d'énumération comme Name_Without_Spaces, et lorsque vous voulez une description, utilisez Name_Without_Spaces.ToString().Replace('_', ' ')pour remplacer les traits de soulignement par des espaces.

Coda
la source
8
Il s'agit d'une solution très inélégante. Envisagez d'utiliser la solution fournie par @Bryan
Johann