我发现了一种扩展方法,可以使用自定义属性中存储的值对枚举进行排序。
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();
}
如您所见,此方法现在可与具有用于比较的任何值类型(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)
获取内部的枚举类型>
希望这会有所帮助