Ottenere attributi del valore di Enum


483

Vorrei sapere se è possibile ottenere attributi dei enumvalori e non di enumse stesso? Ad esempio, supponiamo che io abbia il seguente enum:

using System.ComponentModel; // for DescriptionAttribute

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

Quello che voglio è dato il tipo enum, produce 2 tuple del valore della stringa enum e la sua descrizione.

Il valore è stato facile:

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

Ma come posso ottenere il valore dell'attributo descrizione da popolare Tuple.Desc? Posso pensare a come farlo se l'attributo appartiene a enumse stesso, ma sono in perdita su come ottenerlo dal valore di enum.




2
lo spazio dei nomi richiesto per la descrizione è System.ComponentModel
John M

Non puoi semplicemente usare System.ComponentModel e semplicemente usare il tuo tipo di attributo; non c'è davvero niente di così speciale DescriptionAttribute.
jrh

Risposte:


482

Questo dovrebbe fare quello che ti serve.

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;

10
Facoltativamente, utilizzare type.GetFields (BindingFlags.Public | BindingFlags.Static) per ottenere tutti i memInfos contemporaneamente.
TrueWill,

4
Ho dovuto scrivere typeof (FunkyAttributesEnum), ma a parte questo ha funzionato bene. Grazie.
Greg Randall,

@AlexK Non vedo che la classe Enum abbia una proprietà NameWithoutSpaces1. Da dove proviene FunkyAttributesEnum.NameWithoutSpaces1?
Don

2
@Don, è il nome del membro enum dalla domanda del PO.
MEMark

288

Questo pezzo di codice dovrebbe darti un piccolo metodo di estensione su qualsiasi enum che ti permetta di recuperare un attributo generico. Credo che sia diverso dalla funzione lambda sopra perché è più semplice da usare e leggermente - devi solo passare nel tipo generico.

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

19
L'utilizzo sarebbe quindi: stringa desc = myEnumVariable.GetAttributeOfType <DescriptionAttribute> () .Description;
Brad Rem,

2
Mi piace questo più di quello di Scott, perché l'uso è più pulito qui (meno battitura a macchina), quindi +1 :)
nawfal

3
Se non esiste alcun attributo, questo non lancia un IndexOutOfRangeException?
Erik Philips,

6
usare meglio type.GetMember (Enum.GetName (type, enumVal)) per memInfo come enumVal.ToString () potrebbe non essere affidabile per diverse lingue.
Lin Song Yang,

2
Qual è il punto di chiamare GetCustomAttributes()quindi ottenere il primo elemento invece di chiamare GetCustomAttribute()?
Tigrou,

81

Questa è un'implementazione generica che utilizza un lambda per la selezione

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

Chiamalo così:

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

4
Questo è fantastico Dobbiamo solo fare attenzione se il valore di enumerazione indicato è una combinazione (consentita da FlagsAttribute). In questo caso, enumeration.GetType().GetMember(enumeration.ToString())[0]fallirà.
remio,

Il più breve che potresti scrivere:, ma devi value.GetType().GetField(value.ToString()).GetCustomAttributes(false).OfType<T>‌​().SingleOrDefault()ammettere che il tuo modo esplicito è migliore.
nawfal,

2
Aggiungo anche GetDescription di stringa statica pubblica (questa enumerazione Enum) {return enumeration.GetAttributeValue <DescriptionAttribute, String> (x => x.Description); } in questo modo è solo targetLevel.GetDescription ();
MarkKGreenway,

65

Ho unito un paio di risposte qui per creare una soluzione un po 'più estensibile. Lo sto fornendo nel caso in cui sia utile a chiunque in futuro. Pubblicazione originale qui .

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

}

Questa soluzione crea una coppia di metodi di estensione su Enum. Il primo consente di utilizzare la riflessione per recuperare qualsiasi attributo associato al proprio valore. Il secondo chiama in particolare recupera DescriptionAttributee restituisce il suo Descriptionvalore.

Ad esempio, considera l'utilizzo DescriptionAttributedell'attributo daSystem.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
}

Per utilizzare il metodo di estensione sopra riportato, è sufficiente chiamare quanto segue:

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

o

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

Nell'ultima riga, intendi "attributo. Descrizione"? attributo return == null? value.ToString (): attributo.Descrizione;
Jeson Martajaya,

2
Adoro questa soluzione, ma c'è un bug. Il metodo GetAttribute presuppone che il valore enum abbia un attributo Description e quindi genera un'eccezione quando la lunghezza degli attributi è 0. Sostituisci gli attributi "return (T) [0];" con "return (attributi. Lunghezza> 0? (T) attributi [0]: null);"
Simon Gymer,

@SimonGymer grazie per il suggerimento - Ho aggiornato di conseguenza. :)
Troy Alford,

38

Oltre alla risposta di AdamCrawford , ho ulteriormente creato metodi di estensione più specializzati che ne alimentano per ottenere la descrizione.

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

quindi, per ottenere la descrizione, è possibile utilizzare il metodo di estensione originale come

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

o potresti semplicemente chiamare il metodo di estensione qui come:

string desc = myEnumVariable.GetAttributeDescription();

Il che dovrebbe rendere il tuo codice un po 'più leggibile.


16

Una fodera fluente ...

Qui sto usando il DisplayAttributeche contiene sia l' Namee Descriptionproprietà.

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

Esempio

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

Produzione

Name: Sea cruise 
Description: Cruising on a dinghy

2
Lo uso anche io, è la più pulita di tutte le risposte! +1
Mafii,

Questo sembra essere abbastanza utile! Thnx
Irf,

7

Ecco il codice per ottenere informazioni da un attributo Display. Utilizza un metodo generico per recuperare l'attributo. Se l'attributo non viene trovato, converte il valore enum in una stringa con caso pascal / cammello convertito in caso titolo (codice ottenuto qui )

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

E questo è il metodo di estensione per le stringhe per la conversione in maiuscolo / minuscolo:

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

4

Ho implementato questo metodo di estensione per ottenere la descrizione dai valori enum. Funziona con tutti i tipi di enumerazioni.

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

la versione generica della stessa soluzione è già stata pubblicata. imo, meglio.
nawfal,

4

Ottieni il dizionario da enum.

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

Ora chiamalo come ...

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

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

3

Ecco la versione .NET Core della risposta di AdamCrawford, usando 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];
    }
}

Non credo che .NET Core (o meglio, Standard ora) abbia GetMember, quindi non sono sicuro di come funzioni.
Jeff, il

È in System.Reflection.TypeExtensions, ho rivisto la mia risposta per elencare questo.
vinto il

1
Grazie, grazie. Ho pensato che potrebbero esserci delle estensioni in gioco.
Jeff, il

3

Aggiunta della mia soluzione per Net Framework e NetCore.

L'ho usato per la mia implementazione di 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";
    }
}

Questo non funziona per NetCore, quindi l'ho modificato per fare questo:

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

Esempio di enumerazione:

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

Esempio di utilizzo per l'aggiunta statica:

var myDescription = myEnum.Description();

2

Sfruttando alcune delle più recenti funzionalità del linguaggio C #, puoi ridurre il conteggio delle righe:

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

Ho questa risposta per impostare una casella combinata da un enum attributi che era eccezionale.

Ho quindi bisogno di codificare il contrario in modo da poter ottenere la selezione dalla casella e restituire l'enum nel tipo corretto.

Ho anche modificato il codice per gestire il caso in cui mancava un attributo

Per i vantaggi della prossima persona, ecco la mia soluzione 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
Amico, ho visto tante soluzioni stupide e inspiegabili e la tua l'ha ucciso. Grazie mille <3
Kadaj,

2

Se il tuo enumcontiene un valore come Equalspotresti imbatterti in alcuni bug usando alcune estensioni in molte risposte qui. Questo perché normalmente si presume che typeof(YourEnum).GetMember(YourEnum.Value)restituisca solo un valore, che è il MemberInfotuo enum. Ecco una versione leggermente più sicura della risposta di 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

Questo metodo di estensione otterrà una rappresentazione in forma di stringa di un valore enum usando XmlEnumAttribute. Se non è presente alcun XmlEnumAttribute, esso torna a 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

E se vuoi l'elenco completo dei nomi, puoi fare qualcosa del genere

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

0

Ragazzi, se aiuta, condividerò con voi la mia soluzione: Definizione dell'attributo personalizzato:

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

Ora perché ne avevo bisogno all'interno della definizione di HtmlHelper dell'estensione 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");
    }
}

Spero che sia d'aiuto


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             
    }

Ora produrrà un errore in questo caso 1 "Uguale"

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

quindi se è lo stesso nome enum di ritorno anziché il nome visualizzato perché enumMember.GetCustomAttribute () diventa nullo se displayname e il nome enum sono uguali .....


0

In alternativa, è possibile effettuare le seguenti operazioni:

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

    }

0

Ecco come l'ho risolto senza utilizzare helper o estensioni personalizzati con .NET core 3.1.

Classe

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

Rasoio

@using Enumerations

foreach (var name in Html.GetEnumSelectList(typeof(YourEnum)))
{
    <h1>@name.Text</h1>
}

1
considera di rispondere alla domanda usando più di come hai risolto "esso" - inizia riconoscendo il problema e spiegando come pensi che questo risolva "esso". Ricorda che la tua risposta potrebbe essere fuori dal contesto tra qualche anno e sarebbe quindi quasi inutile. Aggiungendone di più, aggiungere un po 'di contesto aumenterebbe la tua risposta e la sua possibile rilevanza storico / archivistica
OldFart

0

Le prestazioni contano

Se vuoi prestazioni migliori, questa è la strada da percorrere:

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

Perché questo ha prestazioni migliori?

Poiché i metodi integrati utilizzano tutti un codice molto simile a questo, tranne per il fatto che eseguono anche un sacco di altro codice che non ci interessa . Il codice Enum di C # è abbastanza orribile in generale.

Il codice sopra è stato Linq-ified e ottimizzato, quindi contiene solo i bit che ci interessano.

Perché il codice integrato è lento?

Innanzitutto per quanto riguarda Enum.ToString () -vs- Enum.GetName (..)

Usa sempre quest'ultimo. (O meglio ancora nessuno dei due, come sarà chiaro di seguito.)

ToString () usa quest'ultima internamente, ma di nuovo fa anche un sacco di altre cose che non vogliamo, ad esempio cerca di combinare bandiere, stampare numeri ecc. Siamo interessati solo alle costanti definite all'interno dell'enum.

Enum.GetName a sua volta ottiene tutti i campi, crea un array di stringhe per tutti i nomi, usa il ToUInt64 sopra su tutti i loro RawConstantValues ​​per creare un array UInt64 di tutti i valori, ordina entrambi gli array in base al valore UInt64 e infine ottiene il nome da l'array di nomi eseguendo una ricerca binaria nell'array UInt64 per trovare l'indice del valore desiderato.

... e poi buttiamo via i campi e gli array ordinati usano quel nome per ritrovare il campo.

Una sola parola: "Ugh!"


-1

In alternativa, è possibile effettuare le seguenti operazioni:

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

E ottieni la descrizione con quanto segue:

string s = description[FunkyAttributesEnum.NameWithoutSpaces1];

Secondo me questo è un modo più efficiente di fare ciò che vuoi realizzare, poiché non è necessaria alcuna riflessione.


2
Certo, ma la riflessione non è così grave come la gente si immagina di essere.
Bryan Rowe,

Non dire che è male - lo uso sempre. Tuttavia, viene spesso utilizzato inutilmente. :)
Ian P,

44
Questa soluzione allontana la descrizione dall'enum stesso, creando almeno due grossi problemi. Innanzitutto, se qualcuno aggiunge una nuova costante enum, dovrà sapere di andare in questo altro posto per aggiungere anche una voce. Gli attributi sono un chiaro segno per un manutentore di ciò che devono fare. Il mio secondo problema è che è solo molto più codice. Gli attributi sono compatti.
scobi,

1
@scott ma ti consente di specificare il tuo ordine ed escludere i valori che non vuoi visualizzare, il che è quasi sempre quello che voglio davvero
Simon_Weaver

-2

Puoi anche definire un valore enum come Name_Without_Spaces, e quando vuoi una descrizione usa Name_Without_Spaces.ToString().Replace('_', ' ')per sostituire i caratteri di sottolineatura con spazi.


8
Questa è una soluzione molto elegante. Prendi in considerazione l'idea di utilizzare la soluzione fornita da @Bryan
Johann il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.