0

I have a StringValue attribute for enums values, so I could attach a description to each value:

public class StringValueAttribute : Attribute
{
    public string Value { get; private set; }

    public StringValueAttribute(string value)
    {
        Value = value;
    }
}

And that is how I use it:

enum Group
{
    [StringValue("Computer Science")]
    ComputerScience,

    [StringValue("Software Engineering")]
    SoftwareEngineering,

    // ... additional values follow.
}

I have a method that retrieves the StringValue given the enum value:

public static string GetStringValue(Enum value)
{
    Type type = value.GetType();
    FieldInfo fieldInfo = type.GetField(type.ToString());
    StringValueAttribute[] attributes = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];

    string stringValue = null;
    if (attributes.Length > 0)
    {
        stringValue = attributes[0].Value;
    }

    return stringValue;
}

I want to have another method that gets an enum (the enum itself, not a value) and retrieves an IEnumerable using the GetStringValue method. I am not sure how to accomplish that. How could a method like this look like?


Edit: this question is not a duplicate of How to get C# Enum description from value?. I know how to get an enum attribute value, and I actually have a method in the question that does exactly that. My question is how to enumerate all the attributes in an enum.

dbc
  • 104,963
  • 20
  • 228
  • 340
Michael Haddad
  • 4,085
  • 7
  • 42
  • 82
  • You mean you want a generic method `GetStringValues()`? – dbc Dec 19 '17 at 18:40
  • 1
    You can use the existing `DescriptionAttribute` instead of your own custom attribute. For the enumeraiton, `Enum.GetValues(typeof(EnumType)).Cast().Select(/*call your method*/)` – 15ee8f99-57ff-4f92-890c-b56153 Dec 19 '17 at 18:41
  • @dbc - Something like that. However, [here](https://stackoverflow.com/a/27101267/1925272) it is suggested to not make such methods generic. – Michael Haddad Dec 19 '17 at 18:45
  • 1
    Also, typo: `FieldInfo fieldInfo = type.GetField(value.ToString());` -- you're passing `type.ToString()`, not `value.ToString()` – 15ee8f99-57ff-4f92-890c-b56153 Dec 19 '17 at 18:46
  • @EdPlunkett - Thanks. I do not understand: should I write `value.ToString()` instead? – Michael Haddad Dec 19 '17 at 18:50
  • @EdPlunkett - I am not able to make your code work. Here is what I wrote: `Enum.GetValues(typeof(Group)).Cast().Select(g => EnumsUtility.GetStringValue(g));`. also, could you write it in an answer? – Michael Haddad Dec 19 '17 at 18:54
  • @Vikhram - please read the question. It's really not the same. – Michael Haddad Dec 19 '17 at 18:56
  • 1
    @Sipo That works for me. dbc has just posted essentially the solution I was about to suggest, so I saved myself some typing and just upvoted him. – 15ee8f99-57ff-4f92-890c-b56153 Dec 19 '17 at 18:58
  • @Vikhram - my question is not how to get a custom attribute from an enum, the question is how to enumerate all of these attributes. – Michael Haddad Dec 19 '17 at 19:00
  • @Sipo That question and its accepted answer do actually cover everything needed for your answer: If you can get all the values for an enum type, and if you can get a particular attribute for each value, the rest is just putting it all in a loop. – 15ee8f99-57ff-4f92-890c-b56153 Dec 19 '17 at 20:14
  • @EdPlunkett - [In the documentation](https://msdn.microsoft.com/en-us/library/system.componentmodel.descriptionattribute(v=vs.110).aspx), Microsoft writes that the `DescriptionAttribute` should be used with *properties and events*. Should I really use it for enum values? – Michael Haddad Dec 20 '17 at 20:29
  • 1
    @Sipo It’s just metadata, and it’s often used on enum values. There isn’t any harm that can be done by it. Of course, by the same token there’s no harm in writing your own. – 15ee8f99-57ff-4f92-890c-b56153 Dec 20 '17 at 20:35

2 Answers2

2

The most straightforward way to do this is with a generic, though you could always pass in an instance of your specific Enum, get its type, then return the StringValue values for all its values:

public static class EnumExtensions
{
    public static IEnumerable<string> GetStringValues<TEnum>() where TEnum : struct, IConvertible, IComparable, IFormattable
    {
        return Enum.GetValues(typeof(TEnum))
            .Cast<Enum>()
            .Select(e => e.GetStringValue())
            .ToList();
    }

    public static IEnumerable<string> GetStringValuesOfType(Enum value)
    {
        return Enum.GetValues(value.GetType())
            .Cast<Enum>()
            .Select(e => e.GetStringValue())
            .ToList();
    }

    public static string GetStringValue(this Enum value)
    {
        Type type = value.GetType();
        FieldInfo fieldInfo = type.GetField(value.ToString());
        StringValueAttribute[] attributes = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];

        string stringValue = null;
        if (attributes.Length > 0)
        {
            stringValue = attributes[0].Value;
        }

        return stringValue;
    }
}

Notes:

  • There is no where TEnum : Enum constraint in c#. Restricting TEnum to be struct, IConvertible, IComparable, IFormattable is mostly sufficient.

  • That being said, there is a cunning trick to apply an enum constraint which is shown in this answer to Enum type constraints in C# by SLaks. (I didn't use it in this answer though since it's really very cunning.)

  • As noted in @EdPlunkett's comment you need to pass value.ToString() to type.GetField() since you're getting the field corresponding to that specific incoming enum value.

Sample fiddle

dbc
  • 104,963
  • 20
  • 228
  • 340
1

This should work:

static void Main(string[] args)
{
    foreach (var item in GetStringNames<Group>())
    {
        Console.WriteLine(item);
    }
}
public static string GetStringValue(Enum value)
{
    Type type = value.GetType();
    FieldInfo fieldInfo = type.GetField(value.ToString());
    StringValueAttribute[] attributes = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];

    string stringValue = null;
    if (attributes.Length > 0)
    {
        stringValue = attributes[0].Value;
    }

    return stringValue;
}

public static IEnumerable<string> GetStringNames<T>()
{
    var type = typeof(T);

    if (type.IsEnum == false)
    {
        throw new ArgumentException("T must be an Enum type");
    }

    var values = type.GetEnumValues();

    foreach (var item in values)
    {
        yield return GetStringValue((Enum)item);
    }
}
rokkerboci
  • 1,167
  • 1
  • 7
  • 14