I have an enum like this:
enum MyEnum{
[Order(1)]
ElementA = 1,
[Order(0)]
ElementB = 2,
[Order(2)]
ElementC = 3
}
And I want to li
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
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
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;
}
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>();