2

I am trying to get the DisplayAttribute properties working for an enum, so I can list out the values available (to expose to a RESTful API).

I have an enumeration as follows:

/// <summary>
/// Available Proposal Types
/// </summary>
public enum ProposalTypes
{
    Undefined = 0,

    /// <summary>
    /// Propose an administrative action.
    /// </summary>
    [Display(Name = "Administrative", Description = "Propose an administrative action.")]
    Administrative,

    /// <summary>
    /// Propose some other action.
    /// </summary>
    [Display(Name = "Miscellaneous", Description = "Propose some other action.")]
    Miscellaneous
}

I then made some helper methods like so:

    /// <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
    {
        var type = enumValue.GetType();
        var typeInfo = type.GetTypeInfo();
        var attributes = typeInfo.GetCustomAttributes<TAttribute>();
        var attribute = attributes.FirstOrDefault();
        return attribute;
    }

    /// <summary>
    /// Returns a list of possible values and their associated descriptions for a type of enumeration.
    /// </summary>
    /// <typeparam name="TEnum"></typeparam>
    /// <returns></returns>
    public static IDictionary<string, string> GetEnumPossibilities<TEnum>() where TEnum : struct
    {
        var type = typeof(TEnum);
        var info = type.GetTypeInfo();
        if (!info.IsEnum) throw new InvalidOperationException("Specified type is not an enumeration.");


        var results = new Dictionary<string, string>();
        foreach (var enumName in Enum.GetNames(type)
            .Where(x => !x.Equals("Undefined", StringComparison.CurrentCultureIgnoreCase))
            .OrderBy(x => x, StringComparer.CurrentCultureIgnoreCase))
        {
            var value = (Enum)Enum.Parse(type, enumName);
            var displayAttribute = value.GetAttribute<DisplayAttribute>();
            results[enumName] = $"{displayAttribute?.Name ?? enumName}: {displayAttribute?.Description ?? enumName}";
        }
        return results;
    }

The usage for this would be:

var types = Reflection.GetEnumPossibilities<ProposalTypes>();

What seems to be happening, though, is in the GetAttribute<TAttribute> method, when I attempt to get the attribute I'm looking for with:

var attributes = typeInfo.GetCustomAttributes<TAttribute>();

...the resultant value is an empty enumeration, thus returning back a null value. From everything I've read, that should work just fine, and I should get back the associated DisplayAttribute... but I get back a null value.

What am I doing wrong?

Jeremy Holovacs
  • 22,480
  • 33
  • 117
  • 254
  • Out of curiosity, what are you doing with this Dictionary (return value of `GetEnumPossibilities`) at the end? If you are returning this somewhere as JSON you are going through a lot of trouble unnecessarily. JSON.NET will serialize your attributes properly. – hyankov Feb 20 '17 at 15:36
  • @HristoYankov I am using this to create an endpoint that defines the possible types to inform an API consumer front end. – Jeremy Holovacs Feb 20 '17 at 15:45

1 Answers1

5

The problem is that you are looking for attributes on the type ProposalTypes, not the values of the type. See this Question for info on getting the attributes of the enum values.

More precisely in GetAttribute you'll need to get the member that represents your specific value and call GetCustomAttributes on that. Your method will then look like this:

public static TAttribute GetAttribute<TAttribute>(this Enum enumValue) where TAttribute : Attribute
{
    var type = enumValue.GetType();
    var typeInfo = type.GetTypeInfo();
    var memberInfo = typeInfo.GetMember(enumValue.ToString());
    var attributes = memberInfo[0].GetCustomAttributes<TAttribute>();
    var attribute = attributes.FirstOrDefault();
    return attribute;
}
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Chris
  • 27,210
  • 6
  • 71
  • 92
  • 1
    Hmm. I guess I was looking at an enum value as its own type, and that is not what C# looks at it as. Thanks for the help, that was very frustrating. – Jeremy Holovacs Feb 20 '17 at 15:50
  • Yeah, I can see how you'd have trouble starting with that sort of assumption. My debug hint would be that if you'd looked at what `GetType` returned you'd have hopefully been pointed in the right direction of realising that the values weren't types themselves. I had to go look up how to get the attribute off the values though. ;-) – Chris Feb 20 '17 at 15:52