26

I have the following helper method in a ViewModelBase class, which is inherited by other view Models:

public string GetEnumName<T>(Enum value)
        {
            Type enumType = typeof(T);
            var enumValue = Enum.GetName(enumType, value);
            MemberInfo member = enumType.GetMember(enumValue)[0];

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

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

            return outString;
        }

I then call this from the view like this:

<p>
@{var rel = Model.GetEnumDisplayName<Enums.wheteverEnum>(Model.wheteverEnum); }
@rel
</p>

Question is - can I work this method so I don't have to tell it the type of the enum? Basically I'd like todo this for all enums:

@Model.GetEnumDisplayName(Model.wheteverEnum)

No typeof, no T, no need to add a reference to the Enums namespace in the View...

Possible?

1

7 Answers 7

54

You can simply remove the type parameter and make it an extension method.

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

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

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

        return outString;
    }

    @Model.wheteverEnum.DisplayName()
Sign up to request clarification or add additional context in comments.

4 Comments

+1 Very nice. It used the original code plus added the code implementation of the extension method including how to call it.
For completeness sake, you should add a check that there are any DisplayAttributes applied to the enum value and return value.ToString() as a default if there aren't any. Otherwise you'll get an IndexOutOfRangeException when you call ((DisplayAttribute)attrs[0]).Name
If someone try to call from controller: DisplayName((MyEnum)id);
When i add this extension method to my model which contains enum types, ide report error Extension method must be defined in a non-generic static class and when I change my model class to static class, i got tons of other errors which generated due to static definitions. I don't know where to add this snippet? I also created a static base-class for models however I cannot inherit non-static models from a base static model class.
7

Could you not write this as an extension method? Something like...

public static class EnumExtensions
{
  public static string ToDescription(this Enum e)
  {
     var attributes = (DisplayAttribute[])e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DisplayAttribute), false);
     return attributes.Length > 0 ? attributes[0].Description : string.Empty;
  }
}

Usage:

@Model.WhateverEnum.ToDescription();

Comments

5

Nice work @jrummell!

I've added a small tweak below which captures the scenario where an enum doesn't have an associated Display attribute (currently it throws an exception)

/// <summary>
/// Gets the DataAnnotation DisplayName attribute for a given enum (for displaying enums values nicely to users)
/// </summary>
/// <param name="value">Enum value to get display for</param>
/// <returns>Pretty version of enum (if there is one)</returns>
/// <remarks>
/// Inspired by :
///     http://stackoverflow.com/questions/9328972/mvc-net-get-enum-display-name-in-view-without-having-to-refer-to-enum-type-in-vi
/// </remarks>
public static string DisplayFor(this Enum value) {
    Type enumType = value.GetType();
    var enumValue = Enum.GetName(enumType, value);
    MemberInfo member = enumType.GetMember(enumValue)[0];
    string outString = "";

    var attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
    if (attrs.Any()) {
        var displayAttr = ((DisplayAttribute)attrs[0]);

        outString = displayAttr.Name;

        if (displayAttr.ResourceType != null) {
            outString = displayAttr.GetName();
        }
    } else {
        outString = value.ToString();
    }

    return outString;
}

Comments

1

The answer of @jrummell in VB.NET for the few of us...

Module ModuleExtension

    <Extension()>
    Public Function DisplayName(ByVal value As System.Enum) As String

        Dim enumType As Type = value.GetType()
        Dim enumValue = System.Enum.GetName(enumType, value)
        Dim member As MemberInfo = enumType.GetMember(enumValue)(0)

        Dim attrs = member.GetCustomAttributes(GetType(DisplayAttribute), False)
        Dim outString = CType(attrs(0), DisplayAttribute).Name

        If (CType(attrs(0), DisplayAttribute).ResourceType IsNot Nothing) Then
            outString = CType(attrs(0), DisplayAttribute).GetName()
        End If

        Return outString
    End Function


End Module

Comments

1

for anyone who might reach to this question, I found this a lot easier than any thing else: https://www.codeproject.com/articles/776908/dealing-with-enum-in-mvc

Just create a folder "DisplayTemplate" under "Views\Shared", and create an empty view (Name it "Enum") in the new folder "DisplayTemplate", and copy this code to it"

@model Enum

@if (EnumHelper.IsValidForEnumHelper(ViewData.ModelMetadata))
{
    // Display Enum using same names (from [Display] attributes) as in editors
    string displayName = null;
    foreach (SelectListItem item in EnumHelper.GetSelectList(ViewData.ModelMetadata, (Enum)Model))
    {
        if (item.Selected)
        {
            displayName = item.Text ?? item.Value;
        }
    }

    // Handle the unexpected case that nothing is selected
    if (String.IsNullOrEmpty(displayName))
    {
        if (Model == null)
        {
            displayName = String.Empty;
        }
        else
        {
            displayName = Model.ToString();
        }
    }

    @Html.DisplayTextFor(model => displayName)
}
else
{
    // This Enum type is not supported.  Fall back to the text.
    @Html.DisplayTextFor(model => model)
}

Comments

0

Here is an extension method that I've written to do just this... it has a little extra logic in it to parse Enum names and split by capital letters. You can override any name by using the Display Attribute

public static TAttribute GetAttribute<TAttribute>(this ICustomAttributeProvider parameterInfo) where TAttribute : Attribute
{
    object[] attributes = parameterInfo.GetCustomAttributes(typeof(TAttribute), false);
    return attributes.Length > 0 ? (TAttribute)attributes[0] : null;
}
public static bool HasAttribute<TAttribute>(this ICustomAttributeProvider parameterInfo) where TAttribute : Attribute
{
    object[] attributes = parameterInfo.GetCustomAttributes(typeof(TAttribute), false);
    return attributes.Length > 0 ? true : false;
}

public static string ToFriendlyEnum(this Enum type)
{
    return type.GetType().HasAttribute<DescriptionAttribute>() ? type.GetType().GetAttribute<DescriptionAttribute>().Description : type.ToString().ToFriendlyEnum();
}

public static string ToFriendlyEnum(this string value)
{
    char[] chars = value.ToCharArray();
    string output = string.Empty;

    for (int i = 0; i < chars.Length; i++)
    {
        if (i <= 0 || chars[i - 1].ToString() != chars[i - 1].ToString().ToUpper() && chars[i].ToString() != chars[i].ToString().ToLower())
        {
            output += " ";
        }

        output += chars[i];
    }

    return output.Trim();
}

The GetAttribute extension methods could be slightly overkill, but I use them elsewhere in my projects, so they got reused when I wrote my Enum extension. You could easily combine them back into the ToFriendlyEnum(this Enum type) method

Comments

0

The suggested sollutions does not worked for me with MVC3: so the helper below is good.:

    public static string GetEnumDescription(this Enum value)
    {
        Type type = value.GetType();
        string name = Enum.GetName(type, value);
        if (name != null)
        {
            FieldInfo field = type.GetField(name);
            if (field != null)
            {
                string attr = field.GetCustomAttributesData()[0].NamedArguments[0].TypedValue.Value.ToString();
                if (attr == null)
                {
                    return name;
                }
                else
                {
                    return attr;
                }
            }
        }
        return null;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.