285

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>
Amal K
  • 4,359
  • 2
  • 22
  • 44
Pejman
  • 3,784
  • 4
  • 24
  • 33
  • 13
    MVC5 does support DisplayName attribute on enums. – Bart Calixto Feb 18 '14 at 15:05
  • 11
    To be clearer: Only `System.ComponentModel.DataAnnotations.DisplayAttribute`. Not `System.ComponentModel.DisplayNameAttribute`. – kamranicus Oct 29 '15 at 02:49
  • 1
    Does this include use of reflection and therefore impact the performance? 'cos this is gonna be called a LOT of time. – Nico Jul 20 '19 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. – Dai Aug 29 '20 at 06:32
  • As per [tjeerdhans](https://stackoverflow.com/users/160608/tjeerdhans)' [answer](https://stackoverflow.com/a/65705538/14906662) this is now supported by using `@Html.DisplayTextFor(model => model.EnumValue)` – Jeanot Zubler Aug 25 '23 at 13:46

26 Answers26

239

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

Aydin
  • 15,016
  • 4
  • 32
  • 42
  • 3
    Doesn't exist a definition of GetCustomAttribute – Tito Apr 29 '15 at 12:27
  • 4
    @Tito ensure that your project is targeting `.NET Framework 4.5` and that you're including the following namespaces `System.Net` `System.ComponentModel.DataAnnotations` – Aydin Apr 29 '15 at 12:32
  • 8
    using System.Reflection; using System.ComponentModel.DataAnnotations; Was needed for me. – Sinned Lolwut Jan 16 '16 at 13:32
  • @curiousBoy How is `GetAttribute` a terrible naming convention? It retrieves the attribute you specify and uses pascal casing as all public methods should. – Aydin Feb 17 '19 at 02:35
  • @Aydin I'm pretty sure he was making a joke about names like "It's summer". Ha. Ha. :-) – Daniel Jun 24 '19 at 18:58
  • @Aydin How to use this method with Linq to SQL? – habib Jul 25 '19 at 09:47
  • Instead of `.GetMember(enumValue.ToString()) .First()` you can call the `.GetField((enumValue.ToString())` – Peter Csala Jun 10 '20 at 10:40
  • 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. – Bellash Dec 24 '20 at 16:44
213

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>
starball
  • 20,030
  • 7
  • 43
  • 238
Hrvoje Stanisic
  • 2,245
  • 1
  • 14
  • 9
  • 8
    All of the answers use `.ToString`, but from http://stackoverflow.com/q/483794/179311, it says to use `Enum.GetName` instead. – bradlis7 Dec 30 '14 at 18:45
  • value.GetType().GetField(value.ToString()) was exactly what I was looking for ! – cdie Jun 13 '16 at 08:07
  • This answer is fine with some added null checking, but if you aren't using dotfuscation the answer at http://stackoverflow.com/a/4412730/852806 seems simpler. – JsAndDotNet Feb 20 '17 at 21:00
  • I would suggest minors changes: public static IList GetValues(Enum value) could be public static IList GetValues(T value). EnumHelper to => public static class EnumHelper where T : struct, IConvertible. Maybe static contructor? static EnumHelper() { if (!typeof(T).IsEnum) { throw new ArgumentException("T must be an enumerated type"); } } – Tom Feb 19 '18 at 08:58
185

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

Community
  • 1
  • 1
Todd
  • 12,995
  • 3
  • 30
  • 25
  • 4
    Besure to add the following namespaces: using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; – Peter Kerr Mar 11 '15 at 15:21
  • 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."} – Casey Crookston Oct 02 '15 at 14:33
  • 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. – Todd Oct 03 '15 at 21:09
  • 11
    I added a null reference check to the result of `GetCustomAttribute()` because for some Enums maybe this is not present. It falls back to `enumValue.ToString()` if the DisplayAttribute was not present. – FirstVertex May 26 '16 at 16:31
  • 2
    I used this to create a `List` that was populated by an Enum with all individual `DisplayAttribute.Name` annotations - this worked perfectly, thank you!! `public List MySelectListItem = new List(); foreach (MyEnum MyEnum in Enum.GetValues(typeof(MyEnum)).Cast().Where(x => x != MyEnum.Default)) { MySelectListItem.Add(new SelectListItem() { Text = MyEnum.GetDisplayName(), Value = ((int)MyEnum).ToString() }); }` – Hopper Jun 09 '17 at 20:31
  • 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. – Bellash Dec 24 '20 at 16:46
77

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"

Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59
  • 1
    You should be careful with .First(). This will throw an exception for example if your enum name is "Equals" – Vahagn Nahapetyan Jun 05 '18 at 14:03
  • 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! – Youp Bernoulli Jun 06 '18 at 14:33
  • 2
    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. – Alex34758 Jul 23 '18 at 10:27
  • 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. – Bellash Dec 24 '20 at 16:46
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)
1_bug
  • 5,505
  • 4
  • 50
  • 58
  • @SegmentationFault why? Can you describe your problem? Which version of .NET/MVC do you use? What error have you got? Please be more specific. – 1_bug Aug 31 '16 at 12:17
  • 7
    Because it only works for Dropdowns, not anywhere else. – Segmentation Fault Sep 01 '16 at 06:47
  • 2
    Doesn't seem to exist in .net core – Lonefish Jan 19 '17 at 15:40
  • 3
    .net core uses Html.GetEnumSelectList(typeof(YourEnum)) @Lonefish – Patrick Mcvay Mar 29 '17 at 17:20
  • 2
    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 – Developer May 08 '17 at 00:47
19

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.

Sinjai
  • 1,085
  • 1
  • 15
  • 34
15

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,
}
tjeerdhans
  • 1,058
  • 10
  • 13
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?

Community
  • 1
  • 1
maximpa
  • 1,958
  • 13
  • 16
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>
}
Sea_Ocean
  • 309
  • 3
  • 8
  • 1
    I would add a check on the GetDisplayName method return string.IsNullOrEmpty(retVal) ? enumValue.ToString() : retVal; – Sniipe Feb 26 '20 at 11:12
8

With Core 2.1,

public static string GetDisplayName(Enum enumValue)
{
  return enumValue.GetType()?
 .GetMember(enumValue.ToString())?[0]?
 .GetCustomAttribute<DisplayAttribute>()?
 .Name;
}
Deniz aydın
  • 91
  • 1
  • 4
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>
Dmytro
  • 16,668
  • 27
  • 80
  • 130
  • 1
    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.` – Muflix Apr 02 '20 at 12:14
6

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());
}
avs099
  • 10,937
  • 6
  • 60
  • 110
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.

alexn
  • 57,867
  • 14
  • 111
  • 145
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>();
}
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
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
}
Peter Kerr
  • 1,649
  • 22
  • 33
  • 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 (http://stackoverflow.com/questions/31319251/displayname-with-enums-in-c-sharp-mvc) 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! – Karinne Jul 09 '15 at 14:32
  • Updated the code to better handle nulls when you don't have Display Name set for some of the enum values - might help – Peter Kerr Jul 09 '15 at 16:32
  • That still didn't work. I updated my question on http://stackoverflow.com/questions/31319251/displayname-with-enums-in-c-sharp-mvc with the error message. Thanks for the help! – Karinne Jul 10 '15 at 11:48
3

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>
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>
Yasin Sunni
  • 282
  • 7
  • 9
  • 1
    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(); } – Tolga Nov 02 '20 at 01:10
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".
Desmond
  • 406
  • 5
  • 7
2

It is maybe cheating, but it's works:

 @foreach (var yourEnum in Html.GetEnumSelectList<YourEnum>())
 {
     @yourEnum.Text
 }
IceMaur
  • 66
  • 6
  • 1
    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. – ejcortes Jan 12 '23 at 17:42
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();
    }
Pavel
  • 652
  • 7
  • 10
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>
gl3yn
  • 301
  • 1
  • 3
  • 13
1

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

    }

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();
        }
    }
Kryszal
  • 1,663
  • 14
  • 20
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();
    }
}
Red
  • 3,030
  • 3
  • 22
  • 39
0

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") 
M.Hazara
  • 137
  • 9
0

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;