按自定义属性排序枚举

问题描述 投票:0回答:1

我发现了一种扩展方法,可以使用自定义属性中存储的值对枚举进行排序。

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在另一个项目中声明。

如何更改此方法以实现此目的?

c# enums extension-methods custom-attributes
1个回答
0
投票

我将尝试提供对我对问题的理解的解决方案。

据我所知,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();
}

如您所见,此方法现在可与具有用于比较的任何值类型(int,字符串,任何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)获取内部的枚举类型>

希望这会有所帮助

© www.soinside.com 2019 - 2024. All rights reserved.