309

I've got a property in my model called Promotion that its type is a flag enum called UserPromotion. Members of my enum have display attributes set as follows:

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

Now I want to be able to create say a ul in my view to show the selected values of my Promotion property. This is what I have done so far but the problem is that how can I get the display names here?

<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>
5
  • 13
    MVC5 does support DisplayName attribute on enums. Commented Feb 18, 2014 at 15:05
  • 12
    To be clearer: Only System.ComponentModel.DataAnnotations.DisplayAttribute. Not System.ComponentModel.DisplayNameAttribute. Commented Oct 29, 2015 at 2:49
  • 1
    Does this include use of reflection and therefore impact the performance? 'cos this is gonna be called a LOT of time. Commented Jul 20, 2019 at 12:17
  • 1
    @Nico The trick is to cache the results in a static readonly field. The values only need to be read from reflection only once. Commented Aug 29, 2020 at 6:32
  • 1
    As per tjeerdhans' answer this is now supported by using @Html.DisplayTextFor(model => model.EnumValue) Commented Aug 25, 2023 at 13:46

28 Answers 28

255

One liner - Fluent syntax

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

Example

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

Output

Which season is it?
It's summer

Sign up to request clarification or add additional context in comments.

9 Comments

Doesn't exist a definition of GetCustomAttribute
@Tito ensure that your project is targeting .NET Framework 4.5 and that you're including the following namespaces System.Net System.ComponentModel.DataAnnotations
using System.Reflection; using System.ComponentModel.DataAnnotations; Was needed for me.
@curiousBoy How is GetAttribute<TAttribute> a terrible naming convention? It retrieves the attribute you specify and uses pascal casing as all public methods should.
@Aydin I'm pretty sure he was making a joke about names like "It's summer". Ha. Ha. :-)
|
219

UPDATE

First solution was focused on getting display names from enum. Code below should be exact solution for your problem.

You can use this helper class for enums:

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

public static class EnumHelper<T>
    where T : struct, Enum // This constraint requires C# 7.3 or later.
{
    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)
    {
        var resourceKeyProperty = resourceManagerProvider.GetProperty(resourceKey,
            BindingFlags.Static | BindingFlags.Public, null, typeof(string),
            new Type[0], null);
        if (resourceKeyProperty != null)
        {
            return (string)resourceKeyProperty.GetMethod.Invoke(null, null);
        }

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

And then you can use it in your view as following:

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

4 Comments

All of the answers use .ToString, but from stackoverflow.com/q/483794/179311, it says to use Enum.GetName instead.
value.GetType().GetField(value.ToString()) was exactly what I was looking for !
This answer is fine with some added null checking, but if you aren't using dotfuscation the answer at stackoverflow.com/a/4412730/852806 seems simpler.
I would suggest minors changes: public static IList<T> GetValues(Enum value) could be public static IList<T> GetValues(T value). EnumHelper<T> to => public static class EnumHelper<T> where T : struct, IConvertible. Maybe static contructor? static EnumHelper() { if (!typeof(T).IsEnum) { throw new ArgumentException("T must be an enumerated type"); } }
191

Building on Aydin's great answer, here's an extension method that doesn't require any type parameters.

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

NOTE: GetName() should be used instead of the Name property. This ensures that the localized string will be returned if using the ResourceType attribute property.

Example

To use it, just reference the enum value in your view.

@{
    UserPromotion promo = UserPromotion.SendJobOffersByMail;
}

Promotion: @promo.GetDisplayName()

Output

Promotion: Send Job Offers By Mail

6 Comments

Besure to add the following namespaces: using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection;
Slick solution, but I get {"Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions."}
Looking at other SO answers for this error message (I am unfamiliar with it), it appears that you might be using this from within an Html helper method (like @Html.DisplayFor(m => m.myEnum.GetDisplayName()), which won't work, because they expect the evaluated expression to yield a property or something similar. You should use the bare enum value like in the example above.
I added a null reference check to the result of GetCustomAttribute<DisplayAttribute>() because for some Enums maybe this is not present. It falls back to enumValue.ToString() if the DisplayAttribute was not present.
I used this to create a List<SelectListItem> that was populated by an Enum with all individual DisplayAttribute.Name annotations - this worked perfectly, thank you!! 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() }); }
|
80

Based on Aydin's answer I would suggest a less "duplicatious" implementation (because we could easily get the Type from the Enum value itself, instead of providing it as a parameter 😉:

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

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

Now we can use it very clean in this way:

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

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

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

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

Season.Summer.GetDisplayName();

Which results in

"The Summer"

4 Comments

You should be careful with .First(). This will throw an exception for example if your enum name is "Equals"
I understand the "danger" with First(). In this particular case it doesn't seem an issue. Because it is an extension method where this must be a valid (not null) Enum value. Otherwise calling the method would already throw (which is a responsibility of the calling code). This makes that GetType() will for sure provide the correct Enum Type in which enumvalue for sure will be a member. But GetCustomAttribute might return a null value so I provided a non-exceptional version of the method to return null when the chain of method calls has a null return value somewhere. Thanks!
For the second variant of your code, it seems like there is no need to use null-conditional operator after GetMember because this method always returns an array of MemberInfo and never returns null. And for me it seems that it is better to use FirstOrDefault instead of just First. Then the using of null-conditional operator after FirstOrDefault will be seen consistent.
You should consider check if the ResourceType is not null, in order to load the resource string. In Multilanguage applications, the display name is loaded from resource.
30

If you are using MVC 5.1 or upper there is simplier and clearer way: just use data annotation (from System.ComponentModel.DataAnnotations namespace) like below:

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

And in view, just put it into proper html helper:

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

5 Comments

@SegmentationFault why? Can you describe your problem? Which version of .NET/MVC do you use? What error have you got? Please be more specific.
Because it only works for Dropdowns, not anywhere else.
Doesn't seem to exist in .net core
.net core uses Html.GetEnumSelectList(typeof(YourEnum)) @Lonefish
if we want to use the @Html.DisplayFor(yourEnumField) we can put a Enum.cshtml in the DisplayTemplates directory (in shared directory). in this file we need to put just 2 lines. the first is: "@model Enum" the second is: "@GetDisplayName(Model)." the GetDisplayName method needs to be as in @Bernoulli IT answare
26

In .NET5, I used DisplayTextFor without needing helper or extension methods:

@Html.DisplayTextFor(m => m.SomeEnumProperty)

Where SomeEnumProperty has a value of:

public enum MyEnum
{
    [Display(Name = "Not started")]
    NotStarted = 0,
    [Display(Name = "Weird display name instead of just 'Started'")]
    Started = 1,
}

5 Comments

This is definitely the answer!
this needs to be higher up!
@gurkan No. It isn't. There was no .NET 5 in 2012.
@TheincredibleJan Even when I was writing the comment above the answer was already starting with "In .NET 5"
If this isn't Awesome then I don't know what is !!! It is definitely THE solution for ASP.NET CORE projects (works in ASP.NET [CORE] 6). Thank you!
23

Building on Todd's great answer which built on Aydin's great answer, here's a generic extension method which doesn't require any type parameters.

/// <summary>
/// Gets human-readable version of enum.
/// </summary>
/// <returns>effective DisplayAttribute.Name of given enum.</returns>
public static string GetDisplayName<T>(this T enumValue) where T : IComparable, IFormattable, IConvertible // C# 7.3+: where T : struct, Enum
{
    if (!typeof(T).IsEnum) // Not needed in C# 7.3+ with above updated constraint
        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();
}

I needed this for my project because something like the below code, where not every member of the enum has a DisplayAttribute, throws an exception with Todd's solution:

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

If this is a complicated solution to a simple problem, please let me know, but this was the fix I used.

Comments

11

You could use Type.GetMember Method, then get the attribute info using 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;

There were a few similar posts here:

Getting attributes of Enum's value

How to make MVC3 DisplayFor show the value of an Enum's Display-Attribute?

Comments

10

For ASP.Net Core 3.0, this worked for me (credit to previous answerers).

My Enum class:

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 Model Class:

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

An example of a razor view displaying a label and a drop-down list. Notice the drop-down list does not require a helper method:

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

1 Comment

I would add a check on the GetDisplayName method return string.IsNullOrEmpty(retVal) ? enumValue.ToString() : retVal;
8

With Core 2.1,

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

Comments

7

combining all edge-cases together from above:

  • enum members with base object members' names (Equals, ToString)
  • optional Display attribute

here is my code:

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

1 Comment

Nice solution that handles the optional Display attribute. Thanks!
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>

1 Comment

Does not work :/ I am getting an error InvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
4

You need to use a bit of reflection in order to access that attribute:

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;

I recommend wrapping this method in a extension method or perform this in a view model.

Comments

4

I'm sorry to do this, but I couldn't use any of the other answers as-is and haven't time to duke it out in the comments.

Uses C# 6 syntax.

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

Comments

4

For just displaying enum's display name attribute just use Microsoft.AspNetCore.Mvc.Rendering's

@Html.DisplayFor(x => EnumType.EnumValue)

That's would be enough.

For displaying SelectList write as following:

 <select id="someIdForTheEndPoint" asp-items="Html.GetEnumSelectList<EnumType>()">
     <option selected="selected" value="">Select value</option>
 </select>

Comments

3

Building further on Aydin's and Todd's answers, here is an extension method that also lets you get the name from a resource file

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

and use it like

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

3 Comments

I'm trying to get this working for my project but I get an error with the "new ResourceManager(resource).GetString(name);" line. I had asked a question (stackoverflow.com/questions/31319251/…) and I was sent here. When I view the "ResourceManager(resource)" while running it returns "Resources.Enums.resource". Any help would be greatly appreciated. Thank you!
Updated the code to better handle nulls when you don't have Display Name set for some of the enum values - might help
That still didn't work. I updated my question on stackoverflow.com/questions/31319251/… with the error message. Thanks for the help!
2

I have two solutions for this Question.

  1. The first solution is on getting display names from 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. The second Solution is on getting display name from enum name but that will be enum split in developer language it's called 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>

1 Comment

Love the SplitOnCapitals approach here! I rewrote it though using just StringBuilder which is more efficient than RegEx: public static string SplitOnCapitals(this string text) { var sb = new StringBuilder(text); for (int i = sb.Length-1; i > 0; i--) { if (char.IsUpper(sb[i])) { sb.Insert(i, ' '); } } return sb.ToString(); }
2

2020 Update: An updated version of the function provided by many in this thread but now for C# 7.3 onwards:

Now you can restrict generic methods to enums types so you can write a single method extension to use it with all your enums like this:

The generic extension method:

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

The enum:

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

How to use it:

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

Bonus, Enums with Flags: If you are dealing with normal enums the function above is enough, but if any of your enums can take multiple values with the use of flags then you will need to modify it like this (This code uses C#8 features):

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

    } 

The enum with flags:

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

How to use it:

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

Comments

2

It is maybe cheating, but it's works:

 @foreach (var yourEnum in Html.GetEnumSelectList<YourEnum>())
 {
     @yourEnum.Text
 }

1 Comment

I used to do this, but it felt so hackish :-) I upvoted because it works. You can filter by value to get what you want.
2

The below code support some cute features!

  1. Support nullable enums
  2. Support Resource Files (If you used it)
using System.Linq;
using System.Reflection;

namespace Dtat;

public static class EnumHelper : object
{
    static EnumHelper()
    {
    }

    public static string? GetDisplayName(this System.Enum? enumValue)
    {
        if (enumValue is null)
        {
            return null;
        }

        var currentType =
            enumValue.GetType();

        if (currentType is null)
        {
            return enumValue.ToString();
        }

        var membersInfo =
            currentType.GetMember(name: enumValue.ToString())
            .FirstOrDefault();

        if (membersInfo is null)
        {
            return enumValue.ToString();
        }

        var displayAttribute =
            // using System.Reflection;
            membersInfo.GetCustomAttribute
            <System.ComponentModel.DataAnnotations.DisplayAttribute>();

        if (displayAttribute is null)
        {
            return enumValue.ToString();
        }

        var name =
            displayAttribute.Name;

        if (name is null)
        {
            return enumValue.ToString();
        }

        if (displayAttribute.ResourceType is null)
        {
            return name;
        }

        var resourceType =
            displayAttribute.ResourceType;

        var resourceManager = new System.Resources
            .ResourceManager(resourceSource: resourceType);

        var value =
            resourceManager.GetString(name: name);

        if (value is null)
        {
            return name;
        }

        return value;
    }
}

1 Comment

This turns out to be a decent one !
1

I want to contribute with culture-dependent GetDisplayName enum extension. Hope this will be usefull for anyone googling this answer like me previously:

"standart" way as Aydin Adn and Todd mentioned:

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

"Culture-dependent" way:

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

Comments

1

This worked in Asp.Net MVC 5
In your model class User.cs

public enum Expertise
    {
        [Display(Name = "JUNIOR")]
        JUNIOR = 0,
        [Display(Name = "SENIOR")]
        SENIOR = 1
    }

    public class User
    {
        public int Id                   { get; set; }
        [Required]
        public string Name              { get; set; }
        // the type must be the Enum class name
        public Expertise ExpertiseLevel { get; set; }
    }

In your View Index.cshtml

<div>
    <h4>User</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Name)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Name)
        </dd>
        // This is the Property Name
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ExpertiseLevel)
        </dt>
        // This is the Value
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ExpertiseLevel)
        </dd>
    </dl>
</div>

On a side note:
ExpertiseLevel is still an int
To retrieve it in your form, for ex. in Create.cshtml, you need to retrieve the value as 0 or 1, as below:

<div class="form-group">
    <label asp-for="ExpertiseLevel" class="control-label"></label>
        <span class="float-right" data-toggle="buttons">
                    
         <label asp-for="ExpertiseLevel" class="btn btn-outline-secondary" for="juniorCheckbox">
             <input asp-for="ExpertiseLevel" type="radio" class="d-none" id="juniorCheckbox" value="0" checked>
             Junior</label>
                    
         <label asp-for="ExpertiseLevel" class="btn btn-outline-secondary" for="expertCheckbox">
             <input asp-for="ExpertiseLevel" type="radio" class="d-none" id="expertCheckbox" value="1">
                    Expert</label>
      </span>
      <span asp-validation-for="ExpertiseLevel" class="text-danger"></span>
</div>

Comments

1

Here is an implementation that uses a ConcurrentDictionary to cache enum value display names when they are fetched for the first time. So the slow reflection code does not need to run more than once per application lifetime for each enum value.

using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

namespace MyNamespace;

public static class EnumDisplayNameGetter
{
    private static readonly ConcurrentDictionary<Enum, string> _displayNameCache = new();

    public static string GetDisplayName(this Enum enumValue)
    {
        ArgumentNullException.ThrowIfNull(enumValue);

        return _displayNameCache.GetOrAdd(enumValue,
            ev =>
            {
                DisplayAttribute? displayAttribute = GetDisplayAttribute(ev);
                return displayAttribute?.GetName() ?? ev.ToString();
            }
        );
    }

    private static DisplayAttribute? GetDisplayAttribute(Enum enumValue)
    {
        Type enumType = enumValue.GetType();
        FieldInfo? fieldInfo = enumType.GetField(enumValue.ToString(),
            BindingFlags.Public | BindingFlags.Static);
        return fieldInfo?.GetCustomAttribute<DisplayAttribute>();
    }
}

The extension method GetDisplayName() is thread-safe and can be used in multithreaded applications like ASP.NET apps.

My implementation is derived from another implementation that I found in the OpenAPI.NET project.

The information in this answer came from an article that I wrote on my website.

1 Comment

Microsoft.OpenApi.Extensions is now encompassed in Microsoft.OpenApi as of v2.0.0. Since I had to update code anyway to correct using references, I instead opted to use the extension code above. I am still scratching my head slightly that your code seems to return the correct casing of the DisplayName defined for a property when the OpenApi code must have been forcing it lower case. Not sure what that is about yet, but this code work (maybe better) than the code you based it on. Thank you!
0

Based on previous answers I've created this comfortable helper to support all DisplayAttribute properties in a readable way:

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

Comments

0

I tried doing this as an edit but it was rejected; I can't see why.

The above will throw an exception if you call it with an Enum that has a mix of custom attributes and plain items, e.g.

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

So I've modified the code ever so slightly to check for custom attributes before trying to access them, and use the name if none are found.

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

Comments

0

When using Microsoft.OpenApi.Extensions then above answers are no longer needed.

Having a model

using Microsoft.OpenApi.Attributes;

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
}

You can simply use

season.GetDisplayName();

The code which is included in Microsoft.OpenApi

namespace Microsoft.OpenApi.Extensions
{
    /// <summary>
    /// Enumeration type extension methods.
    /// </summary>
    public static class EnumExtensions
    {
        /// <summary>
        /// Gets an attribute on an enum field value.
        /// </summary>
        /// <typeparam name="T">The type of the attribute to retrieve.</typeparam>
        /// <param name="enumValue">The enum value.</param>
        /// <returns>
        /// The attribute of the specified type or null.
        /// </returns>
        public static T GetAttributeOfType<T>(this Enum enumValue) where T : Attribute
        {
            var type = enumValue.GetType();
            var memInfo = type.GetMember(enumValue.ToString()).First();
            var attributes = memInfo.GetCustomAttributes<T>(false);
            return attributes.FirstOrDefault();
        }

        /// <summary>
        /// Gets the enum display name.
        /// </summary>
        /// <param name="enumValue">The enum value.</param>
        /// <returns>
        /// Use <see cref="DisplayAttribute"/> if exists.
        /// Otherwise, use the standard string representation.
        /// </returns>
        public static string GetDisplayName(this Enum enumValue)
        {
            var attribute = enumValue.GetAttributeOfType<DisplayAttribute>();
            return attribute == null ? enumValue.ToString() : attribute.Name;
        }
    }
}

Comments

-1

Using MVC5 you could use:

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
}

then if you want to create a dropdown selector you can use:

@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select") 

Comments

-1

assume that your enum name is OrderState, Use this code:

@Html.DropDownList("selectList", new SelectList(Html.GetEnumSelectList<OrderState>(), "Value", "Text",ViewBag.selectedOrderState), new {@id="OrderState", @class = "form-control" })                

and set selected option in backend:

 var selectedOrderState = ..Data.OrderState.GetHashCode();
        ViewBag.selectedOrderState = selectedOrderState;

        

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.