按自定义属性对枚举进行排序

Sorting enum by a custom attribute

我找到了一种扩展方法,可以使用存储在自定义属性中的值来订购枚举。

public static class EnumExtenstions
{
    public static IEnumerable<TEnum> EnumGetOrderedValues<TEnum>(this Type enumType)
    {
        var fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
        var orderedValues = new List<Tuple<int, TEnum>>();
        foreach (var field in fields)
        {
            var orderAtt = field.GetCustomAttributes(typeof(EnumOrderAttribute), false).SingleOrDefault() as EnumOrderAttribute;
            if (orderAtt != null)
            {
                orderedValues.Add(new Tuple<int, TEnum>(orderAtt.Order, (TEnum)field.GetValue(null)));
            }
        }

        return orderedValues.OrderBy(x=>x.Item1).Select(x=>x.Item2).ToList();
    }
}

我想对此进行更改,因此我将 EnumOrderAttribute 作为参数传递并计算出其每次迭代的值。 EnumOrderAttribute 在不同的项目中声明。

我怎样才能改变这个方法来完成这个?

我会尝试根据我对问题的理解提供解决方案。

据我了解,OP 希望为传入属性类型的所有枚举类型提供一个通用的值排序方法,并找到一种使用此属性获取比较值的方法。

这是我的想法:

假设我们有一个属性,我们用它装饰我们的枚举值以进行排序:

[AttributeUsage(AttributeTargets.Field)]
public class MyEnumOrderAttribute : Attribute
{
    public MyEnumOrderAttribute(int order)
    {
        Order = order;
    }

    public int Order { get; set; }
}

让我们有一个枚举,其值使用我们的属性进行修饰:

public enum MyEnum
{
    [MyEnumOrder(2)]
    MyVal0 = 0,
    [MyEnumOrder(1)]
    MyVal1,
    [MyEnumOrder(3)]
    MyVal2,
    [MyEnumOrder(0)]
    MyVal3
}

这个枚举和属性可以是我们的,也可以来自第三方程序集,我们希望我们的方法使用这个属性对值进行排序,所以,我们需要传递属性的类型(这已经是一个泛型参数),我们需要传递一个函数来获取属性实例的比较值。

因此;这是我们的扩展方法的新实现:(稍后关于这是扩展方法的一些注释)

public static IEnumerable<TEnum> EnumGetOrderedValues<TEnum, TAttribute>
    (this Type enumType, Func<TAttribute, IComparable> valueExtractor)
    where TAttribute : Attribute
{
    var fields = typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static);
    var orderedValues = new List<Tuple<IComparable, TEnum>>();
    foreach (var field in fields)
    {
        var orderAtt = field.GetCustomAttributes(typeof(TAttribute), false).SingleOrDefault() as TAttribute;
        if (orderAtt != null)
        {
            orderedValues.Add(new Tuple<IComparable, TEnum>(valueExtractor(orderAtt), (TEnum)field.GetValue(null)));
        }
    }

    return orderedValues.OrderBy(x => x.Item1).Select(x => x.Item2).ToList();
}

如您所见,此方法现在适用于具有用于比较的任何值类型(整数、字符串、任何 IComparable)的任何属性类型

下面是使用方法:

var orderedValues = typeof(MyEnum).EnumGetOrderedValues<MyEnum, MyEnumOrderAttribute>(x => x.Order);

请不要将x => x.Order作为获取属性值的函数进行比较。我们可以在这里传递任何实现。

有序值的输出是:

    foreach (MyEnum orderedValue in orderedValues)
    {
        Console.WriteLine(orderedValue);
    }

MyVal3
MyVal1
MyVal0
MyVal2

编辑:注意该方法是一种扩展方法。

该方法是对Type的扩展,我认为没有必要。

目前,我们这样调用这个方法:

typeof(MyEnum).EnumGetOrderedValues<MyEnum, MyEnumOrderAttribute>(x => x.Order);

扩展方法已经在其第一个泛型参数中采用枚举类型,并且可以在任何类型(typeof(string)?)上调用此方法,这可能会造成混淆。

为什么不把它作为一个静态方法呢?如果可以通过扩展在枚举本身上调用此方法,例如 MyEnum.EnumGetOrderedValues,那将是有意义的。但既然不可能,我们只能将其改为静态方法:

public static IEnumerable<TEnum> EnumGetOrderedValues<TEnum, TAttribute>
    (Func<TAttribute, IComparable> valueExtractor)
    where TAttribute : Attribute

并使用 typeof(TEnum)

获取里面的枚举类型

希望这对您有所帮助