关于C#:使用泛型方法获取我的枚举属性的List

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

首先,我们有这个基本的枚举。

1
2
3
4
5
6
7
8
9
10
11
public enum E_Levels {

    [ValueOfEnum("Low level")]
    LOW,

    [ValueOfEnum("Normal level")]
    NORMAL,

    [ValueOfEnum("High level")]
    HIGH
}

我想得到一个List,无论枚举是什么。类似于Extensions.GetValuesOfEnum(),它可以返回一个List,其中包含"低水平"、"正常水平"和"高水平"。

Stackof帮助我获得了一个值属性:

1
2
3
4
5
6
7
8
9
public static class Extensions {

    public static string ToValueOfEnum(this Enum value) {

        FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
        ValueOfEnum[] attribs = fieldInfo.GetCustomAttributes(typeof(ValueOfEnum), false) as ValueOfEnum[];
        return attribs.Length > 0 ? attribs[0].value : null;
    }
}

我可以调用这个方法,不管枚举是什么:E_Levels.LOW.ToValueOfEnum()

此外,Stackof还帮助我获得了一个特定枚举的List。我在一个控制器中做了这个方法:

1
2
3
4
5
6
7
8
9
private List<string> GetLevels() {

List<string> levelsToReturn = new List<string>();
var levels = Enum.GetValues(typeof(E_Levels)).Cast<E_Levels>();
foreach(E_Levels l in levels)
    levelsToReturn.Add(l.ToValueOfEnum());

return levelsToReturn;
}

但这种方法要求我为每个枚举重写相同的方法。
所以我尝试添加这个通用方法我的类扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class Extensions {

    public static string ToValueOfEnum(this Enum value) {...}

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

        List<string> levelsToReturn = new List<string>();
        var levels = Enum.GetValues(typeof(T)).Cast<T>();
        foreach(T l in levels)
        levelsToReturn.Add(l.ToValueOfEnum());

        return levelsToReturn;
    }
}

但在我的前臂,.ToValueOfEnum()是一种未知的方法。所以我遇到了麻烦,我希望我能找到一种方法来避免对每个枚举重复重写相同的方法…


让我们尝试让这个更一般的目的。

我有安全的方法,可以推广的价值属性enum抢了。这会给你快速访问的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
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();
    }
}

使用这个,你可以创造一些queries得到什么你想要的。

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

所以你的GetValuesOf()方法(这是不是一个伟大的名称为这一专业的方法imho)可以像这样写的:

1
2
3
4
5
6
7
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();
}

现在你可以像调用该方法相比:

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


attribute。网已经有相同的,所以你可以使用这一DescriptionValueOfEnum相反。

什么关于dynamic和延伸,在type和以下的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
[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
}

结果输出:

1
2
3
Low level
Normal level
High level


你可能尝试把ToValueOfEnum铸造(Enum)(object)l,不断变化的安全object,或只是inline的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}

这里是一个解决方案-线使用铸造的方法:

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

在的情况下,你不是在T不清晰为什么不是像E_LevelsEnum被公认为是安全的,那是因为你没有,T : enum来指定。不幸的是,你不能来指定,在C #(即使它的clr支持),所以其他检查方法,如runtime /假设(如我想在这里暗示)或代码修改后编译时(例如unconstrained -旋律)有大做。