0
votes

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.

2
You mean you want a generic method GetStringValues<TEnum>()?dbc
You can use the existing DescriptionAttribute instead of your own custom attribute. For the enumeraiton, Enum.GetValues(typeof(EnumType)).Cast<EnumType>().Select(/*call your method*/)15ee8f99-57ff-4f92-890c-b56153
Also, typo: FieldInfo fieldInfo = type.GetField(value.ToString()); -- you're passing type.ToString(), not value.ToString()15ee8f99-57ff-4f92-890c-b56153
@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
@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

2 Answers

2
votes

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

1
votes

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