问题
I have an enum like this:
enum MyEnum{
[Order(1)]
ElementA = 1,
[Order(0)]
ElementB = 2,
[Order(2)]
ElementC = 3
}
And I want to list its elements sorted by a custom order attribute I wrote, so that I get a list of items sorted.
I am getting the Description Attribute but just for one element like this:
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
It may be something the same but need to work on all Enum and return a list or another sorted enum.
回答1:
Assume the OrderAttribute
class is as follows:
public class OrderAttribute : Attribute
{
public readonly int Order;
public OrderAttribute(int order)
{
Order = order;
}
}
The helper method to obtain sorted values of enum:
public static T[] SortEnum<T>()
{
Type myEnumType = typeof(T);
var enumValues = Enum.GetValues(myEnumType).Cast<T>().ToArray();
var enumNames = Enum.GetNames(myEnumType);
int[] enumPositions = Array.ConvertAll(enumNames, n =>
{
OrderAttribute orderAttr = (OrderAttribute)myEnumType.GetField(n)
.GetCustomAttributes(typeof(OrderAttribute), false)[0];
return orderAttr.Order;
});
Array.Sort(enumPositions, enumValues);
return enumValues;
}
回答2:
If I clearly understood your issue, here could be solution like this:
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();
}
}
usage:
var result = typeof(enumType).EnumGetOrderedValues<enumType>();
回答3:
Given
[AttributeUsage(AttributeTargets.Field)]
public class OrderAttribute : Attribute
{
public readonly int Order;
public OrderAttribute(int order)
{
Order = order;
}
}
public static class OrderHelper
{
public static int GetOrder<TEnum>(TEnum value) where TEnum : struct
{
int order;
if (!OrderHelperImpl<TEnum>.Values.TryGetValue(value, out order))
{
order = int.MaxValue;
}
return order;
}
private static class OrderHelperImpl<TEnum>
{
public static readonly Dictionary<TEnum, int> Values;
static OrderHelperImpl()
{
var values = new Dictionary<TEnum, int>();
var fields = typeof(TEnum).GetFields(BindingFlags.Static | BindingFlags.Public);
int unordered = int.MaxValue - 1;
for (int i = fields.Length - 1; i >= 0; i--)
{
FieldInfo field = fields[i];
var order = (OrderAttribute)field.GetCustomAttributes(typeof(OrderAttribute), false).FirstOrDefault();
int order2;
if (order != null)
{
order2 = order.Order;
}
else
{
order2 = unordered;
unordered--;
}
values[(TEnum)field.GetValue(null)] = order2;
}
Values = values;
}
}
}
You can then:
int o1 = OrderHelper.GetOrder(MyEnum.ElementA);
int o2 = OrderHelper.GetOrder(MyEnum.ElementB);
int o3 = OrderHelper.GetOrder(MyEnum.ElementC);
So sorting is like:
var myenums = new[] { MyEnum.ElementA, MyEnum.ElementB, MyEnum.ElementC };
Array.Sort(myenums, (p, q) => OrderHelper.GetOrder(p).CompareTo(OrderHelper.GetOrder(q)));
or for LINQ:
var myenums = new[] { MyEnum.ElementA, MyEnum.ElementB, MyEnum.ElementC };
var sorted = myenums.OrderBy(x => OrderHelper.GetOrder(x));
The OrderHelper
"caches" the ordering inside a OrderHelperImpl<TEnum>
. The values of the enum are extracted by knowing that in enums the values are public static
fields (you can easily see it here).
Values without an Order
are ordered in the same ordering they are present in the enum
, by using the greatest possible values of an int
just below int.MaxValue
回答4:
public class OrderAttribute : Attribute
{
public int priority;
public OrderAttribute(int priority)
{
this.priority = priority;
}
}
public enum Test
{
[Order(1)] value1 = 1,
[Order(2)] value2 = 2,
[Order(0)] value3 = 3
}
private static void Main(string[] args)
{
Dictionary<string, int> priorityTable = new Dictionary<string, int>();
var values = Enum.GetValues(typeof (Test)).Cast<Test>();
MemberInfo[] members = typeof (Test).GetMembers();
foreach (MemberInfo member in members)
{
object[] attrs = member.GetCustomAttributes(typeof(OrderAttribute), false);
foreach (object attr in attrs)
{
OrderAttribute orderAttr = attr as OrderAttribute;
if (orderAttr != null)
{
string propName = member.Name;
int priority = orderAttr.priority;
priorityTable.Add(propName, priority);
}
}
}
values = values.OrderBy(n => priorityTable[n.ToString("G")]);
foreach (var value in values)
{
Console.WriteLine(value);
}
Console.ReadLine();
}
This will output:
value3
value1
value2
来源:https://stackoverflow.com/questions/30654151/how-to-sort-enum-using-a-custom-order-attribute