Pejman
Pejman

Reputation: 3964

How to get the Display Name Attribute of an Enum member via MVC Razor code?

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>

Upvotes: 303

Views: 450137

Answers (27)

Dariush Tasdighi
Dariush Tasdighi

Reputation: 400

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

Upvotes: 2

rfcdejong
rfcdejong

Reputation: 2320

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

Upvotes: 0

Youp Bernoulli
Youp Bernoulli

Reputation: 5635

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"

Upvotes: 80

avr-girl
avr-girl

Reputation: 557

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>

Upvotes: 1

Hrvoje Stanisic
Hrvoje Stanisic

Reputation: 2285

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>

Upvotes: 217

Sinjai
Sinjai

Reputation: 1277

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.

Upvotes: 23

MahmoudVahedim
MahmoudVahedim

Reputation: 61

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;

        

Upvotes: 0

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>

Upvotes: 4

IceMaur
IceMaur

Reputation: 97

It is maybe cheating, but it's works:

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

Upvotes: 2

tjeerdhans
tjeerdhans

Reputation: 1158

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

Upvotes: 25

Desmond
Desmond

Reputation: 603

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

Upvotes: 2

Yasin Sunni
Yasin Sunni

Reputation: 292

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>

Upvotes: 2

Sea_Ocean
Sea_Ocean

Reputation: 319

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

Upvotes: 10

avs099
avs099

Reputation: 11227

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

Upvotes: 7

M.Hazara
M.Hazara

Reputation: 137

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

Upvotes: 0

Pavel
Pavel

Reputation: 692

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

Upvotes: 1

Deniz ayd谋n
Deniz ayd谋n

Reputation: 91

With Core 2.1,

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

Upvotes: 8

Red
Red

Reputation: 3267

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

Upvotes: 0

Todd
Todd

Reputation: 13173

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

Upvotes: 191

Aydin
Aydin

Reputation: 15284

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

Upvotes: 250

Ruben Bartelink
Ruben Bartelink

Reputation: 61795

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

Upvotes: 4

Kryszal
Kryszal

Reputation: 1673

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

Upvotes: 0

1_bug
1_bug

Reputation: 5717

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)

Upvotes: 30

Peter Kerr
Peter Kerr

Reputation: 1739

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
}

Upvotes: 3

maximpa
maximpa

Reputation: 1988

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?

Upvotes: 11

Dmytro
Dmytro

Reputation: 17156

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

Upvotes: 6

alexn
alexn

Reputation: 58952

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.

Upvotes: 4

Related Questions