Come ottenere l'attributo del nome visualizzato di un membro Enum tramite il codice del rasoio MVC?


211

Ho una proprietà nel mio modello chiamata "Promozione" che il suo tipo è un enum di bandiera chiamato "UserPromotion". I membri del mio enum hanno gli attributi di visualizzazione impostati come segue:

[Flags]
public enum UserPromotion
{
    None = 0x0,

    [Display(Name = "Send Job Offers By Mail")]
    SendJobOffersByMail = 0x1,

    [Display(Name = "Send Job Offers By Sms")]
    SendJobOffersBySms = 0x2,

    [Display(Name = "Send Other Stuff By Sms")]
    SendPromotionalBySms = 0x4,

    [Display(Name = "Send Other Stuff By Mail")]
    SendPromotionalByMail = 0x8
}

Ora voglio essere in grado di creare un ul nella mia vista per mostrare i valori selezionati della mia proprietà "Promozione". Questo è quello che ho fatto finora, ma il problema è che come posso ottenere i nomi visualizzati qui?

<ul>
    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
    {
        var currentPromotion = (int)Model.JobSeeker.Promotion;
        if ((currentPromotion & aPromotion) == aPromotion)
        {
        <li>Here I don't know how to get the display attribute of "currentPromotion".</li>
        }
    }
</ul>

12
MVC5 supporta l'attributo DisplayName su enum.
Bart Calixto,

10
Per essere più chiari: solo System.ComponentModel.DataAnnotations.DisplayAttribute. Non System.ComponentModel.DisplayNameAttribute.
kamranicus,

1
Questo include l'uso della riflessione e quindi influisce sulle prestazioni? perché questo si chiamerà MOLTO tempo.
Nico,

Risposte:


182

AGGIORNARE

La prima soluzione era focalizzata sull'ottenere nomi visualizzati da enum. Il codice seguente dovrebbe essere la soluzione esatta per il tuo problema.

È possibile utilizzare questa classe di supporto per enum:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumHelper<T>
{
    public static IList<T> GetValues(Enum value)
    {
        var enumValues = new List<T>();

        foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
        {
            enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
        }
        return enumValues;
    }

    public static T Parse(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static IList<string> GetNames(Enum value)
    {
        return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
    }

    public static IList<string> GetDisplayValues(Enum value)
    {
        return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
    }

    private static string lookupResource(Type resourceManagerProvider, string resourceKey)
    {
        foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
        {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
                System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                return resourceManager.GetString(resourceKey);
            }
        }

        return resourceKey; // Fallback with the key name
    }

    public static string GetDisplayValue(T value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        var descriptionAttributes = fieldInfo.GetCustomAttributes(
            typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (descriptionAttributes[0].ResourceType != null)
            return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);

        if (descriptionAttributes == null) return string.Empty;
        return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
    }
}

E poi puoi usarlo nella tua vista come segue:

<ul>
    @foreach (var value in @EnumHelper<UserPromotion>.GetValues(UserPromotion.None))
    {
         if (value == Model.JobSeeker.Promotion)
        {
            var description = EnumHelper<UserPromotion>.GetDisplayValue(value);
            <li>@Html.DisplayFor(e => description )</li>
        }
    }
</ul>

Spero che sia d'aiuto! :)


8
Tutte le risposte usano .ToString, ma da stackoverflow.com/q/483794/179311 , dice Enum.GetNameinvece di usare .
bradlis7,

value.GetType (). GetField (value.ToString ()) era esattamente quello che stavo cercando!
cdie,

Questa risposta è bene con qualche controllo nullo aggiunto, ma se non si utilizza dotfuscation la risposta a stackoverflow.com/a/4412730/852806 sembra più semplice.
HockeyJ

5
In GetDisplayValuesi dovrebbe primo test descriptionAttributes == nullprima di tentare di accedere alla matrice: descriptionAttributes[0]. Altrimenti potresti sollevare un'eccezione e la riga in basso in cui controlli null non sarà mai vera.
Robert S.

Suggerirei modifiche minori: IList statico pubblico <T> GetValues ​​(valore Enum) potrebbe essere IList statico pubblico <T> GetValues ​​(valore T). EnumHelper <T> a => classe statica pubblica EnumHelper <T> dove T: struct, IConvertible. Forse un regolatore statico? static EnumHelper () {if (! typeof (T) .IsEnum) {throw new ArgumentException ("T deve essere un tipo elencato"); }}
Tom,

172

One liner - Sintassi fluida

public static class Extensions
{
    /// <summary>
    ///     A generic extension method that aids in reflecting 
    ///     and retrieving any attribute that is applied to an `Enum`.
    /// </summary>
    public static TAttribute GetAttribute<TAttribute>(this Enum enumValue) 
            where TAttribute : Attribute
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<TAttribute>();
    }
}

Esempio

public enum Season 
{
   [Display(Name = "It's autumn")]
   Autumn,

   [Display(Name = "It's winter")]
   Winter,

   [Display(Name = "It's spring")]
   Spring,

   [Display(Name = "It's summer")]
   Summer
}

public class Foo 
{
    public Season Season = Season.Summer;

    public void DisplayName()
    {
        var seasonDisplayName = Season.GetAttribute<DisplayAttribute>();
        Console.WriteLine("Which season is it?");
        Console.WriteLine (seasonDisplayName.Name);
    } 
}

Produzione

Che stagione è?
È estate


2
Non esiste una definizione di GetCustomAttribute
Tito

3
@Tito si assicura che il tuo progetto sia mirato .NET Framework 4.5e che stai includendo i seguenti spazi dei nomiSystem.Net System.ComponentModel.DataAnnotations
Aydin,

8
utilizzando System.Reflection; utilizzando System.ComponentModel.DataAnnotations; Era necessario per me.
Sinned Lolwut,

1
che terribile convenzione di denominazione!
curiousBoy

@curiousBoy Come è GetAttribute<TAttribute>una terribile convenzione di denominazione? Recupera l'attributo specificato e utilizza l'involucro pascal come dovrebbero fare tutti i metodi pubblici.
Aydin,

137

Sulla base della grande risposta di Aydin , ecco un metodo di estensione che non richiede alcun parametro di tipo.

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<DisplayAttribute>()
                        .GetName();
    }
}

NOTA: utilizzare GetName () anziché la proprietà Name. Ciò garantisce che la stringa localizzata venga restituita se si utilizza la proprietà dell'attributo ResourceType.

Esempio

Per usarlo, fai semplicemente riferimento al valore enum nella tua vista.

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

Produzione

Promozione: inviare offerte di lavoro per posta


4
Assicurati di aggiungere i seguenti spazi dei nomi: using System; utilizzando System.ComponentModel.DataAnnotations; utilizzando System.Linq; utilizzando System.Reflection;
Peter Kerr,

Soluzione semplice, ma ottengo {"I modelli possono essere utilizzati solo con accesso ai campi, accesso alle proprietà, indice di array a dimensione singola o espressioni dell'indicizzatore personalizzate a parametro singolo."}
Casey Crookston,

Guardando altre risposte SO per questo messaggio di errore (non ho familiarità con esso), sembra che potresti utilizzarlo da un metodo di supporto HTML (come @Html.DisplayFor(m => m.myEnum.GetDisplayName()) , che non funzionerà, perché si aspettano che l'espressione valutata produca una proprietà o qualcosa di simile. Dovresti usare il valore enum nudo come nell'esempio sopra.
Todd,

7
Ho aggiunto un controllo di riferimento null al risultato di GetCustomAttribute<DisplayAttribute>()perché per alcuni Enum forse questo non è presente. Ritorna a enumValue.ToString()se DisplayAttribute non era presente.
H Dog,

1
Ho usato questo per creare un List<SelectListItem>popolato da un Enum con tutte le singole DisplayAttribute.Nameannotazioni - ha funzionato perfettamente, grazie !! public List<SelectListItem> MySelectListItem = new List<SelectListItem>(); foreach (MyEnum MyEnum in Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Where(x => x != MyEnum.Default)) { MySelectListItem.Add(new SelectListItem() { Text = MyEnum.GetDisplayName(), Value = ((int)MyEnum).ToString() }); }
Hopper,

61

Sulla base della risposta di Aydin, suggerirei un'implementazione meno "duplicata" (perché potremmo facilmente ottenere Typeil Enumvalore stesso, invece di fornirlo come parametro 😉:

public static string GetDisplayName(this Enum enumValue)
{
    return enumValue.GetType().GetMember(enumValue.ToString())
                   .First()
                   .GetCustomAttribute<DisplayAttribute>()
                   .Name;
}

EDIT (basato sul commento di @Vahagn Nahapetyan)

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

Ora possiamo usarlo molto pulito in questo modo:

public enum Season 
{
    [Display(Name = "The Autumn")]
    Autumn,

    [Display(Name = "The Weather")]
    Winter,

    [Display(Name = "The Tease")]
    Spring,

    [Display(Name = "The Dream")]
    Summer
}

Season.Summer.GetDisplayName();

Che si traduce in

"Il sogno"


1
Di gran lunga la più semplice e la più semplice di tutte le risposte. Grazie!
Casey Crookston,

Dovresti stare attento con .First (). Ciò genererà un'eccezione, ad esempio se il tuo nome enum è "Uguale"
Vahagn Nahapetyan,

Capisco il "pericolo" con First (). In questo caso particolare non sembra un problema. Perché è un metodo di estensione dove thisdeve essere un valore Enum valido (non nullo). Altrimenti, chiamare il metodo verrebbe già lanciato (che è una responsabilità del codice chiamante). Questo rende GetType()sicuramente il tipo di Enum corretto in cui enumvaluesicuramente sarà un membro. Ma GetCustomAttribute potrebbe restituire un valore null, quindi ho fornito una versione non eccezionale del metodo per restituire null quando la catena di chiamate del metodo ha un valore restituito null da qualche parte. Grazie!
Bernoulli IT

1
Per la seconda variante del codice, sembra che non sia necessario utilizzare l'operatore null-condizionale dopo GetMember perché questo metodo restituisce sempre una matrice di MemberInfo e non restituisce mai null. E per me sembra che sia meglio usare FirstOrDefault invece di First. Quindi l'utilizzo dell'operatore null-condizionale dopo FirstOrDefault sarà considerato coerente.
Alex34758,

28

Se stai usando MVC 5.1 o superiore c'è un modo più semplice e chiaro: usa semplicemente l'annotazione dei dati (dallo System.ComponentModel.DataAnnotationsspazio dei nomi) come sotto:

public enum Color
{
    [Display(Name = "Dark red")]
    DarkRed,
    [Display(Name = "Very dark red")]
    VeryDarkRed,
    [Display(Name = "Red or just black?")]
    ReallyDarkRed
}

E in vista, basta inserirlo nel giusto aiuto HTML:

@Html.EnumDropDownListFor(model => model.Color)

@SegmentationFault perché? Puoi descrivere il tuo problema? Quale versione di .NET / MVC usi? Che errore hai? Sii più specifico.
1_bug

6
Perché funziona solo per i Dropdown, non altrove.
Errore di segmentazione

2
Non sembra esistere nel core .net
Lonefish

3
.net core utilizza Html.GetEnumSelectList (typeof (YourEnum)) @Lonefish
Patrick Mcvay

2
se vogliamo usare @ Html.DisplayFor (yourEnumField) possiamo mettere un Enum.cshtml nella directory DisplayTemplates (nella directory condivisa). in questo file dobbiamo inserire solo 2 righe. il primo è: "@model Enum" il secondo è: "@GetDisplayName (Model)." il metodo GetDisplayName deve essere come in @Bernoulli IT answare
Developer

11

È possibile utilizzare il metodo Type.GetMember , quindi ottenere le informazioni sull'attributo utilizzando reflection:

// display attribute of "currentPromotion"

var type = typeof(UserPromotion);
var memberInfo = type.GetMember(currentPromotion.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var description = ((DisplayAttribute)attributes[0]).Name;

C'erano alcuni post simili qui:

Ottenere attributi del valore di Enum

Come fare in modo che MVC3 DisplayPer mostrare il valore di un attributo di visualizzazione di Enum?


8

Sulla base della grande risposta di Todd che si basava sulla grande risposta di Aydin , ecco un metodo di estensione generico che non richiede alcun parametro di tipo.

/// <summary>
/// Gets human-readable version of enum.
/// </summary>
/// <returns>DisplayAttribute.Name property of given enum.</returns>
public static string GetDisplayName<T>(this T enumValue) where T : IComparable, IFormattable, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("Argument must be of type Enum");

    DisplayAttribute displayAttribute = enumValue.GetType()
                                                 .GetMember(enumValue.ToString())
                                                 .First()
                                                 .GetCustomAttribute<DisplayAttribute>();

    string displayName = displayAttribute?.GetName();

    return displayName ?? enumValue.ToString();
}

Ne avevo bisogno per il mio progetto perché qualcosa come il codice seguente, in cui non tutti i membri dell'enum ha un DisplayAttribute, non funziona con la soluzione di Todd:

public class MyClass
{
    public enum MyEnum 
    {
        [Display(Name="ONE")]
        One,
        // No DisplayAttribute
        Two
    }
    public void UseMyEnum()
    {
        MyEnum foo = MyEnum.One;
        MyEnum bar = MyEnum.Two;
        Console.WriteLine(foo.GetDisplayName());
        Console.WriteLine(bar.GetDisplayName());
    }
}
// Output:
//
// ONE
// Two

Se questa è una soluzione complicata a un semplice problema, per favore fatemi sapere, ma questa è stata la correzione che ho usato.


6
<ul>
    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
    {
        var currentPromotion = (int)Model.JobSeeker.Promotion;
        if ((currentPromotion & aPromotion) == aPromotion)
        {
        <li>@Html.DisplayFor(e => currentPromotion)</li>
        }
    }
</ul>

Non funziona: / Ricevo un erroreInvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Muflix

6

Ho due soluzioni per questa domanda.

  1. La prima soluzione è ottenere nomi visualizzati da enum.
public enum CourseLocationTypes
{
    [Display(Name = "On Campus")]
    OnCampus,
    [Display(Name = "Online")]
    Online,
    [Display(Name = "Both")]
    Both
}

public static string DisplayName(this Enum value)
{
    Type enumType = value.GetType();
    string enumValue = Enum.GetName(enumType, value);
    MemberInfo member = enumType.GetMember(enumValue)[0];

    object[] attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
    string outString = ((DisplayAttribute)attrs[0]).Name;

    if (((DisplayAttribute)attrs[0]).ResourceType != null)
    {
        outString = ((DisplayAttribute)attrs[0]).GetName();
    }

    return outString;
}
<h3 class="product-title white">@Model.CourseLocationType.DisplayName()</h3>
  1. La seconda soluzione consiste nell'ottenere il nome visualizzato dal nome enum ma che verrà diviso in enum nella lingua dello sviluppatore si chiama patch.
public static string SplitOnCapitals(this string text)
{
        var r = new Regex(@"
            (?<=[A-Z])(?=[A-Z][a-z]) |
             (?<=[^A-Z])(?=[A-Z]) |
             (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);

        return r.Replace(text, " ");
}
 <div class="widget-box pt-0">
     @foreach (var item in Enum.GetNames(typeof(CourseLocationType)))
     {
         <label class="pr-2 pt-1">
             @Html.RadioButtonFor(x => x.CourseLocationType, item, new { type = "radio", @class = "iCheckBox control-label" })&nbsp; @item.SplitOnCapitals()
         </label>
     }
     @Html.ValidationMessageFor(x => x.CourseLocationType)
 </div>

5

Per ASP.Net Core 3.0, questo ha funzionato per me (merito ai precedenti risponditori).

La mia classe Enum:

using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

public class Enums
{
    public enum Duration
    { 
        [Display(Name = "1 Hour")]
        OneHour,
        [Display(Name = "1 Day")]
        OneDay
    }

    // Helper method to display the name of the enum values.
    public static string GetDisplayName(Enum value)
    {
        return value.GetType()?
       .GetMember(value.ToString())?.First()?
       .GetCustomAttribute<DisplayAttribute>()?
       .Name;
    }
}

My View Classe di modello:

public class MyViewModel
{
    public Duration Duration { get; set; }
}

Un esempio di una vista rasoio che mostra un'etichetta e un elenco a discesa. Si noti che l'elenco a discesa non richiede un metodo di supporto:

@model IEnumerable<MyViewModel> 

@foreach (var item in Model)
{
    <label asp-for="@item.Duration">@Enums.GetDisplayName(item.Duration)</label>
    <div class="form-group">
        <label asp-for="@item.Duration" class="control-label">Select Duration</label>
        <select asp-for="@item.Duration" class="form-control"
            asp-items="Html.GetEnumSelectList<Enums.Duration>()">
        </select>
    </div>
}

Aggiungerei un segno di spunta sul metodo GetDisplayName return string.IsNullOrEmpty (retVal)? enumValue.ToString (): retVal;
Sniipe,

4

Devi usare un po 'di riflessione per accedere a quell'attributo:

var type = typeof(UserPromotion);
var member = type.GetMember(Model.JobSeeker.Promotion.ToString());
var attributes = member[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var name = ((DisplayAttribute)attributes[0]).Name;

Raccomando di racchiudere questo metodo in un metodo di estensione o di eseguirlo in un modello di visualizzazione.


4

Con Core 2.1,

public static string GetDisplayName(Enum enumValue)
{
  return enumValue.GetType()?
 .GetMember(enumValue.ToString())?[0]?
 .GetCustomAttribute<DisplayAttribute>()?
 .Name;
}

4

combinando tutti i casi limite dall'alto:

  • membri enum con i nomi dei membri dell'oggetto base ( Equals, ToString)
  • Displayattributo opzionale

ecco il mio codice:

public enum Enum
{
    [Display(Name = "What a weird name!")]
    ToString,

    Equals
}

public static class EnumHelpers
{
    public static string GetDisplayName(this Enum enumValue)
    {
        var enumType = enumValue.GetType();

        return enumType
                .GetMember(enumValue.ToString())
                .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == enumType)
                .First()
                .GetCustomAttribute<DisplayAttribute>()?.Name ?? enumValue.ToString();
    }
}

void Main()
{
    Assert.Equals("What a weird name!", Enum.ToString.GetDisplayName());
    Assert.Equals("Equals", Enum.Equals.GetDisplayName());
}

Bella soluzione che gestisce l'attributo Display opzionale. Grazie!
Wellspring,

3

Mi dispiace farlo, ma non ho potuto usare nessuna delle altre risposte così com'è e non ho tempo di scriverle nei commenti.

Usa la sintassi C # 6.

static class EnumExtensions
{
    /// returns the localized Name, if a [Display(Name="Localised Name")] attribute is applied to the enum member
    /// returns null if there isnt an attribute
    public static string DisplayNameOrEnumName(this Enum value)
    // => value.DisplayNameOrDefault() ?? value.ToString()
    {
        // More efficient form of ^ based on http://stackoverflow.com/a/17034624/11635
        var enumType = value.GetType();
        var enumMemberName = Enum.GetName(enumType, value);
        return enumType
            .GetEnumMemberAttribute<DisplayAttribute>(enumMemberName)
            ?.GetName() // Potentially localized
            ?? enumMemberName; // Or fall back to the enum name
    }

    /// returns the localized Name, if a [Display] attribute is applied to the enum member
    /// returns null if there is no attribute
    public static string DisplayNameOrDefault(this Enum value) =>
        value.GetEnumMemberAttribute<DisplayAttribute>()?.GetName();

    static TAttribute GetEnumMemberAttribute<TAttribute>(this Enum value) where TAttribute : Attribute =>
        value.GetType().GetEnumMemberAttribute<TAttribute>(value.ToString());

    static TAttribute GetEnumMemberAttribute<TAttribute>(this Type enumType, string enumMemberName) where TAttribute : Attribute =>
        enumType.GetMember(enumMemberName).Single().GetCustomAttribute<TAttribute>();
}

2

Sviluppando ulteriormente le risposte di Aydin e Todd, ecco un metodo di estensione che consente anche di ottenere il nome da un file di risorse

using AppResources;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Resources;

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        var enumMember= enumValue.GetType()
                        .GetMember(enumValue.ToString());

        DisplayAttribute displayAttrib = null;
        if (enumMember.Any()) {
            displayAttrib = enumMember 
                        .First()
                        .GetCustomAttribute<DisplayAttribute>();
        }

        string name = null;
        Type resource = null;

        if (displayAttrib != null)
        {
            name = displayAttrib.Name;
            resource = displayAttrib.ResourceType;
        }

        return String.IsNullOrEmpty(name) ? enumValue.ToString()
            : resource == null ?  name
            : new ResourceManager(resource).GetString(name);
    }
}

e usalo come

public enum Season 
{
    [Display(ResourceType = typeof(Resource), Name = Season_Summer")]
    Summer
}

Sto cercando di farlo funzionare per il mio progetto ma ho un errore con il "nuovo ResourceManager (risorsa) .GetString (nome);" linea. Avevo fatto una domanda ( stackoverflow.com/questions/31319251/… ) e sono stato inviato qui. Quando visualizzo il "ResourceManager (risorsa)" durante l'esecuzione, restituisce "Resources.Enums.resource". Qualsiasi aiuto sarebbe molto apprezzato. Grazie!
Karinne,

Aggiornato il codice per gestire meglio i valori null quando non hai impostato Nome visualizzato per alcuni dei valori enum - potrebbe essere d'aiuto
Peter Kerr

Non funzionava ancora. Ho aggiornato la mia domanda su stackoverflow.com/questions/31319251/… con il messaggio di errore. Grazie per l'aiuto!
Karinne,

1

Voglio contribuire con l'estensione enum GetDisplayName dipendente dalla cultura. Spero che questo sia utile per chiunque googling questa risposta come me in precedenza:

modo "standart" come menzionato da Aydin Adn e Todd :

    public static string GetDisplayName(this Enum enumValue)
    {
        return enumValue
            .GetType()
            .GetMember(enumValue.ToString())
            .First()
            .GetCustomAttribute<DisplayAttribute>()
            .GetName();
    }

Modo "dipendente dalla cultura":

    public static string GetDisplayName(this Enum enumValue, CultureInfo ci)
    {
        var displayAttr = enumValue
            .GetType()
            .GetMember(enumValue.ToString())
            .First()
            .GetCustomAttribute<DisplayAttribute>();

        var resMan = displayAttr.ResourceType?.GetProperty(@"ResourceManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as ResourceManager;

        return resMan?.GetString(displayAttr.Name, ci) ?? displayAttr.GetName();
    }

1

Aggiornamento 2020: una versione aggiornata della funzione fornita da molti in questo thread ma ora per C # 7.3 in poi:

Ora puoi limitare i metodi generici ai tipi di enumerazione in modo da poter scrivere una singola estensione di metodo per usarla con tutti i tuoi enum in questo modo:

Il metodo di estensione generico:

public static string ATexto<T>(this T enumeración) where T : struct, Enum {
    var tipo = enumeración.GetType();
    return tipo.GetMember(enumeración.ToString())
    .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo).First()
    .GetCustomAttribute<DisplayAttribute>()?.Name ?? enumeración.ToString();
} 

L'enum:

public enum TipoImpuesto { 
IVA, INC, [Display(Name = "IVA e INC")]IVAeINC, [Display(Name = "No aplica")]NoAplica };

Come usarlo:

var tipoImpuesto = TipoImpuesto.IVAeINC;
var textoTipoImpuesto = tipoImpuesto.ATexto(); // Prints "IVA e INC".

Bonus, enumerazioni con flag: se hai a che fare con enumerazioni normali la funzione sopra è sufficiente, ma se uno qualsiasi dei tuoi enum può assumere più valori con l'uso di flag, dovrai modificarlo in questo modo (Questo codice usa C # 8 Caratteristiche):

    public static string ATexto<T>(this T enumeración) where T : struct, Enum {

        var tipo = enumeración.GetType();
        var textoDirecto = enumeración.ToString();

        string obtenerTexto(string textoDirecto) => tipo.GetMember(textoDirecto)
            .Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo)
            .First().GetCustomAttribute<DisplayAttribute>()?.Name ?? textoDirecto;

        if (textoDirecto.Contains(", ")) {

            var texto = new StringBuilder();
            foreach (var textoDirectoAux in textoDirecto.Split(", ")) {
                texto.Append($"{obtenerTexto(textoDirectoAux)}, ");
            }
            return texto.ToString()[0..^2];

        } else {
            return obtenerTexto(textoDirecto);
        }

    } 

L'enum con le bandiere:

[Flags] public enum TipoContribuyente {
    [Display(Name = "Común")] Común = 1, 
    [Display(Name = "Gran Contribuyente")] GranContribuyente = 2, 
    Autorretenedor = 4, 
    [Display(Name = "Retenedor de IVA")] RetenedorIVA = 8, 
    [Display(Name = "Régimen Simple")] RégimenSimple = 16 } 

Come usarlo:

var tipoContribuyente = TipoContribuyente.RetenedorIVA | TipoContribuyente.GranContribuyente;
var textoAux = tipoContribuyente.ATexto(); // Prints "Gran Contribuyente, Retenedor de IVA".

0

Sulla base delle risposte precedenti ho creato questo comodo aiuto per supportare tutte le proprietà DisplayAttribute in modo leggibile:

public static class EnumExtensions
    {
        public static DisplayAttributeValues GetDisplayAttributeValues(this Enum enumValue)
        {
            var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute<DisplayAttribute>();

            return new DisplayAttributeValues(enumValue, displayAttribute);
        }

        public sealed class DisplayAttributeValues
        {
            private readonly Enum enumValue;
            private readonly DisplayAttribute displayAttribute;

            public DisplayAttributeValues(Enum enumValue, DisplayAttribute displayAttribute)
            {
                this.enumValue = enumValue;
                this.displayAttribute = displayAttribute;
            }

            public bool? AutoGenerateField => this.displayAttribute?.GetAutoGenerateField();
            public bool? AutoGenerateFilter => this.displayAttribute?.GetAutoGenerateFilter();
            public int? Order => this.displayAttribute?.GetOrder();
            public string Description => this.displayAttribute != null ? this.displayAttribute.GetDescription() : string.Empty;
            public string GroupName => this.displayAttribute != null ? this.displayAttribute.GetGroupName() : string.Empty;
            public string Name => this.displayAttribute != null ? this.displayAttribute.GetName() : this.enumValue.ToString();
            public string Prompt => this.displayAttribute != null ? this.displayAttribute.GetPrompt() : string.Empty;
            public string ShortName => this.displayAttribute != null ? this.displayAttribute.GetShortName() : this.enumValue.ToString();
        }
    }

0

Ho provato a farlo come una modifica ma è stato rifiutato; Non vedo perché.

Quanto sopra genererà un'eccezione se la chiami con un Enum che ha un mix di attributi personalizzati ed elementi semplici, ad es

public enum CommentType
{
    All = 1,
    Rent = 2,
    Insurance = 3,
    [Display(Name="Service Charge")]
    ServiceCharge = 4
}

Quindi ho modificato leggermente il codice per verificare la presenza di attributi personalizzati prima di provare ad accedervi e utilizzare il nome se non ne viene trovato nessuno.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumHelper<T>
{
    public static IList<T> GetValues(Enum value)
    {
        var enumValues = new List<T>();

        foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
        {
            enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
        }
        return enumValues;
    }

    public static T Parse(string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }

    public static IList<string> GetNames(Enum value)
    {
        return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
    }

    public static IList<string> GetDisplayValues(Enum value)
    {
        return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
    }

    private static string lookupResource(Type resourceManagerProvider, string resourceKey)
    {
        foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
        {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
                System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                return resourceManager.GetString(resourceKey);
            }
        }

        return resourceKey; // Fallback with the key name
    }

    public static string GetDisplayValue(T value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());

        var descriptionAttributes = fieldInfo.GetCustomAttributes(
            typeof(DisplayAttribute), false) as DisplayAttribute[];

        if (descriptionAttributes.Any() && descriptionAttributes[0].ResourceType != null)
            return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);

        if (descriptionAttributes == null) return string.Empty;
        return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
    }
}

0

Utilizzando MVC5 è possibile utilizzare:

public enum UserPromotion
{
   None = 0x0,

   [Display(Name = "Send Job Offers By Mail")]
   SendJobOffersByMail = 0x1,

   [Display(Name = "Send Job Offers By Sms")]
   SendJobOffersBySms = 0x2,

   [Display(Name = "Send Other Stuff By Sms")]
   SendPromotionalBySms = 0x4,

   [Display(Name = "Send Other Stuff By Mail")]
   SendPromotionalByMail = 0x8
}

quindi se si desidera creare un selettore a discesa è possibile utilizzare:

@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select") 
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.