Get a List<string> of my enum attributes with a generic method

≡放荡痞女 提交于 2019-11-28 10:23:52
Jeff Mercado

Let's try to keep this more general purpose.

I have an extension method that could grab attributes off of enum values. This would give you quick access to the attributes.

public static class EnumExtensions
{
    public static TAttribute GetAttribute<TAttribute>(this Enum value)
        where TAttribute : Attribute
    {
        var type = value.GetType();
        var name = Enum.GetName(type, value);
        return type.GetField(name)
            .GetCustomAttributes(false)
            .OfType<TAttribute>()
            .SingleOrDefault();
    }
}

Using this, you could create some queries to get what you want.

var valuesOfLevels =
    Enum.GetValues(typeof(E_Levels)).Cast<E_Levels>()
        .Select(level => level.GetAttribute<ValueOfEnumAttribute>().Value);

So your GetValuesOf() method (which is not a great name for such a specialty method IMHO) can be written like this:

public static List<string> GetValuesOf<TEnum>()
    where TEnum : struct // can't constrain to enums so closest thing
{
    return Enum.GetValues(typeof(TEnum)).Cast<Enum>()
               .Select(val => val.GetAttribute<ValueOfEnumAttribute>().Value)
               .ToList();
}

Now you may call the method like so:

var levelValues = GetValueOf<E_Levels>();
// levelValues = { "Low level", "Normal level", "High level" }

You might try casting (Enum)(object)l, changing ToValueOfEnum to take an object, or just inline the method:

public static List<string> GetValuesOf<T>()
{

    List<string> levelsToReturn = new List<string>();
    var levels = Enum.GetValues(typeof(T)).Cast<T>();
    foreach (T value in levels)
    {
        FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
        ValueOfEnum[] attribs = fieldInfo.GetCustomAttributes(typeof(ValueOfEnum), false) as ValueOfEnum[];
        levelsToReturn.Add(attribs.Length > 0 ? attribs[0].value : null);
    }

    return levelsToReturn;
}

Here's a one-line solution using the casting approach:

return new List<string>(Enum.GetValues(typeof(T)).Cast<Enum>().Select(x => x.ToValueOfEnum()));

In case you weren't clear on why T wasn't recognized as an Enum like E_Levels is, that's because you didn't specify that T : enum. Unfortunately, you can't specify that in C# (even though the CLR supports it), so other approaches like runtime checking/assuming (such as what I'm suggesting here) or post-compile code modifications (e.g. unconstrained-melody) have to be done.

.Net already has the same attribute Description so you can use this one instead ValueOfEnum.

What about dynamic and extension on type and following example

[TestFixture]
public sealed class ForTest
{
    [Test]
    public void Test()
    {
        var values = typeof(Levels).ToValues();
        values.ForEach(Console.WriteLine);
    }
}

public static class TypeExtensions
{
    public static List<string> ToValues(this Type value)
    {
        var result = new List<string>();
        var values = ToConcreteValues(value);
        foreach (dynamic item in values)
        {
            Description attribute = GetAttribute<Description>(item);
            result.Add(attribute.Description);
        }
        return result;
    }

    private static dynamic ToConcreteValues(Type enumType)
    {
        Array values = Enum.GetValues(enumType);
        Type list = typeof (List<>);
        Type resultType = list.MakeGenericType(enumType);
        dynamic result = Activator.CreateInstance(resultType);
        foreach (object value in values)
        {
            dynamic concreteValue = Enum.Parse(enumType, value.ToString());
            result.Add(concreteValue);
        }
        return result;
    }

    private static TAttribute GetAttribute<TAttribute>(dynamic value)
        where TAttribute : Attribute
    {
        Type type = value.GetType();
        FieldInfo fieldInfo = type.GetField(Enum.GetName(type, value));
        return (TAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof (TAttribute));
    }
}

public enum Levels
{
    [Description("Low level")]LOW,
    [Description("Normal level")] NORMAL,
    [Description("High level")] HIGH
}

result output:

Low level
Normal level
High level
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!