按自定义属性对枚举进行排序
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)
获取里面的枚举类型
希望这对您有所帮助
我找到了一种扩展方法,可以使用存储在自定义属性中的值来订购枚举。
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)
希望这对您有所帮助