2015-06-04 3 views
10

Ich habe eine Enumeration wie folgt aus:Wie Sortieren Enum mit einem benutzerdefinierten Auftrag Attribut?

enum MyEnum{ 
[Order(1)] 
ElementA = 1, 
[Order(0)] 
ElementB = 2, 
[Order(2)] 
ElementC = 3 
} 

Und ich will seine Elemente durch eine benutzerdefinierte Reihenfolge Attribut sortiert aufzulisten schrieb ich, so dass ich eine Liste von Elementen sortiert bekommen.

ich die Beschreibung Attribut bin immer aber nur für ein Element wie folgt aus:

FieldInfo fi = value.GetType().GetField(value.ToString()); 
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); 

Es kann das gleiche etwas sein, sondern müssen auf alle Enum arbeiten und eine Liste oder eine andere sortierte Enumeration zurück.

+0

In welchem ​​Kontext benötigen Sie diese Liste? In welcher Art von Sammlung speichern Sie die Enum-Werte? – phoog

+0

Am Ende muss ich ein Array von Enum-Werten erhalten, aber sortiert –

Antwort

8

Angenommen, die OrderAttribute Klasse ist wie folgt:

public class OrderAttribute : Attribute 
{ 
    public readonly int Order; 

    public OrderAttribute(int order) 
    { 
     Order = order; 
    } 
} 

Die Hilfsmethode sortierten Werte von ENUM zu erhalten:

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; 
} 
+0

Ich habe kleine Änderungen an Ihrer Lösung vorgenommen, so dass es mit jedem Enum funktioniert und als Antwort hinzugefügt wird, da hier nach einem Kommentar gesucht wird. –

+0

@AmrElgarhy Sie können meine Antwort bearbeiten, falls gewünscht. – Dmitry

+0

können Sie kopieren Sie es auf Ihre Antwort und ich werde meine –

1

Bei

[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; 
     } 
    } 
} 

Sie können dann:

int o1 = OrderHelper.GetOrder(MyEnum.ElementA); 
int o2 = OrderHelper.GetOrder(MyEnum.ElementB); 
int o3 = OrderHelper.GetOrder(MyEnum.ElementC); 

So ist die Sortierung wie:

var myenums = new[] { MyEnum.ElementA, MyEnum.ElementB, MyEnum.ElementC }; 
Array.Sort(myenums, (p, q) => OrderHelper.GetOrder(p).CompareTo(OrderHelper.GetOrder(q))); 

oder für LINQ:

var myenums = new[] { MyEnum.ElementA, MyEnum.ElementB, MyEnum.ElementC }; 
var sorted = myenums.OrderBy(x => OrderHelper.GetOrder(x)); 

Die OrderHelper "caches" die Bestellung innerhalb einer OrderHelperImpl<TEnum>. Die Werte der Enumeration werden extrahiert, indem man weiß, dass in enums die Werte public static Felder sind (Sie können es leicht here sehen).

Werte ohne Order sind in der gleichen Reihenfolge bestellt sie im enum vorhanden sind, indem Sie die größtmögliche Werte eines int mit knapp unter int.MaxValue

+0

Clever - wenn kein Attribut gefunden wird, behält es die relative Reihenfolge von enums und legt sie nach den Enums, die Attribute haben. –

0
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(); 
    } 

erhalten Sie folgende Ausgabe:

value3

Wert1

Wert2

3

Wenn ich klar Ihr Problem verstanden, hier könnte Lösung so aussehen:

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(); 
    } 
} 

Nutzung:

var result = typeof(enumType).EnumGetOrderedValues<enumType>(); 
+1

Warum Typ enumType als Parameter, während ich nicht sehe, werden wir es verwenden? –

+1

Mein Fehler. Das wurde behoben. – Vokinneberg

Verwandte Themen