3

I'm having some hard time with trying to be generic with enums. I've read that it's not that simple, and I can't seem to find a solution.

I'm trying to create a generic function, that for an enum type would return the description for each enum value. I want to keep it generic and not to duplicate this method for each enum type...

Here's what I have so far:

public static KeyValuePair<string, List<KeyValueDataItem>> ConvertEnumWithDescription<T>()
    where T : struct, IConvertible
{
    if (!typeof(T).IsEnum)
    {
        throw new Exception("Type given T must be an Enum");
    }

    var enumType = typeof(T).ToString().Split('.').Last();

    var itemsList = Enum.GetValues(typeof(T))
            .Cast<T>()
            .Select(x => new KeyValueDataItem
            {
                Key = Convert.ToInt32(x),
                Value = GetEnumDescription(Convert.ToInt32(x))
            })
            .ToList();

    var res = new KeyValuePair<string, List<KeyValueDataItem>>(enumType, itemsList);

    return res;
}

public static string GetEnumDescription(Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

    var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute), false);

    if (attributes.Length > 0)
        return attributes[0].Description;

    return value.ToString();
}

The issue I'm currently having is that:

cannot convert from 'int' to 'System.Enum'

When I'm trying to call the function GetEnumDescription. If I convert it to T:

Value = GetEnumDescription((T)(object)Convert.ToInt32(x));

This is the error I'm getting:

cannot convert from 'T' to 'System.Enum'

3 Answers 3

3

Here, try this:

public static KeyValuePair<string, List<KeyValueDataItem>> ConvertEnumWithDescription<T>() where T : struct, IConvertible
    {
        if (!typeof(T).IsEnum)
        {
            throw new Exception("Type given T must be an Enum");
        }

        var enumType = typeof(T).ToString().Split('.').Last();
        var itemsList = Enum.GetValues(typeof(T))
              .Cast<T>()
               .Select(x => new KeyValueDataItem
               {
                   Key = Convert.ToInt32(x),
                   Value = GetEnumDescription<T>(x.ToString())
               })
               .ToList();

        var res = new KeyValuePair<string, List<KeyValueDataItem>>(
            enumType, itemsList);
        return res;

    }

    public static string GetEnumDescription<T>(string value)
    {
        Type type = typeof(T);
        var name = Enum.GetNames(type).Where(f => f.Equals(value, StringComparison.CurrentCultureIgnoreCase)).Select(d => d).FirstOrDefault();

        if (name == null)
        {
            return string.Empty;
        }
        var field = type.GetField(name);
        var customAttribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
        return customAttribute.Length > 0 ? ((DescriptionAttribute)customAttribute[0]).Description : name;
}

Based on: http://www.extensionmethod.net/csharp/enum/getenumdescription

Sign up to request clarification or add additional context in comments.

Comments

1

I took the liberty of modifying some parts of the code, like changing the return types to more C# standard API return values.

You can watch it run here.

public static EnumDescription ConvertEnumWithDescription<T>() where T : struct, IConvertible
{
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("Type given T must be an Enum");
    }

    var enumType = typeof(T).Name;
    var valueDescriptions = Enum.GetValues(typeof (T))
        .Cast<Enum>()
        .ToDictionary(Convert.ToInt32, GetEnumDescription);

    return new EnumDescription
    {
        Type = enumType,
        ValueDescriptions = valueDescriptions
    };

}

public static string GetEnumDescription(Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes =
        (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

    if (attributes.Length > 0)
        return attributes[0].Description;
    return value.ToString();
}

public class EnumDescription
{
    public string Type { get; set; }
    public IDictionary<int, string> ValueDescriptions { get; set; }
}

Comments

0

Modified your code slightly to pass in a Type to the description method and pass the parameter as a string value. This then gets converted back to the appropriate enum type and checked for the description.

public static KeyValuePair<string, List<KeyValueDataItem>> ConvertEnumWithDescription<T>() where T : struct, IConvertible
{
        if (!typeof(T).IsEnum)
        {
            throw new Exception("Type given T must be an Enum");
        }

        var enumType = typeof(T).ToString().Split('.').Last();
        var type = typeof(T);

        var itemsList = Enum.GetValues(typeof(T))
                .Cast<T>()
                .Select(x => new KeyValueDataItem
                {
                    Key = Convert.ToInt32(x),
                    Value = GetEnumDescription<T>(Enum.GetName(typeof(T), x))
                })
                .ToList();

        var res = new KeyValuePair<string, List<KeyValueDataItem>>(
            enumType, itemsList);
        return res;

}       

public static string GetEnumDescription<T>(string enumValue)
{
    var value = Enum.Parse(typeof(T), enumValue);
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes =
        (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

    if (attributes.Length > 0)
        return attributes[0].Description;
    return value.ToString();
}

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.