6

一开始,我们有这个基本的枚举。

public enum E_Levels {

    [ValueOfEnum("Low level")]
    LOW,

    [ValueOfEnum("Normal level")]
    NORMAL,

    [ValueOfEnum("High level")]
    HIGH
}

我想得到一个List<string> enum。类似Extensions.GetValuesOfEnum<E_Levels>()which 的东西可能会返回List<string>“低级别”、“正常级别”和“高级别”。

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

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<string>一个特定的枚举。我在控制器中制作了这个方法:

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

但是这种方式需要我为每个枚举重写相同的方法。
因此,我尝试将此通用方法添加到我的类 Extensions 中:

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

但是在我的foreach中,.ToValueOfEnum()是一个未知的方法。

所以我遇到了麻烦,我希望我能找到一种方法,不要一次又一次地为每个枚举重写相同的方法......

4

3 回答 3

9

让我们尽量保持这个更通用的目的。

我有一个扩展方法可以从枚举值中获取属性。这将使您能够快速访问属性。

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

使用它,您可以创建一些查询来获得您想要的。

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

因此,您的GetValuesOf()方法(恕我直言,这对于这种特殊方法来说并不是一个好名字)可以这样写:

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

现在您可以像这样调用该方法:

var levelValues = GetValueOf<E_Levels>();
// levelValues = { "Low level", "Normal level", "High level" }
于 2012-08-18T22:14:48.623 回答
0

.Net 已经具有相同的属性Description,因此您可以使用此属性ValueOfEnum

关于dynamic和扩展type以及以下示例

[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
}

结果输出:

Low level
Normal level
High level
于 2012-08-19T00:19:38.210 回答
0

您可以尝试 cast (Enum)(object)l,更改ToValueOfEnum为采用object,或者只是内联该方法:

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

这是使用铸造方法的单线解决方案:

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

如果您不清楚为什么T不被识别为Enum喜欢E_Levels,那是因为您没有指定T : enum. 不幸的是,您不能在 C# 中指定它(即使 CLR 支持它),所以其他方法,如运行时检查/假设(例如我在这里建议的)或编译后代码修改(例如unconstrained-melody)有要完成。

于 2012-08-18T22:10:29.180 回答