2011-10-16 11 views
7

Używam wyliczenia z atrybutem flagi jako sposobu śledzenia statusu.Znajdowanie flagi najwyższego zestawu w wartości wyliczeniowej

Przykładem jest następująca:

Created = 1 
Completed = 2 
Dispatched = 4 

bez pisania czegokolwiek zbyt sztywny (jeśli check to zrobić, jeśli sprawdzenie, że to zrobić) chcę, aby być w stanie znaleźć największą flagę który został tak ustawiona w tym przykładzie:

Item.Status = Status.Created | Status.Completed 

sposób mityczny wróci 2 - jako zakończone jest flaga ustawiona o najwyższej wartości.

GetMaxSetFlagValue(Item.Status) // returns 2 

Znalazłem pytania, które dotyczyły rzeczywistego wyliczenia, ale nie wartości, która używa flag. Jestem prawie pewien, że można to osiągnąć dzięki Linq ...?

Odpowiedz

7

coś jak następuje powinno działać:

static int GetMaxSetFlagValue<T>(T flags) where T : struct 
{ 
    int value = (int)Convert.ChangeType(flags, typeof(int)); 
    IEnumerable<int> setValues = Enum.GetValues(flags.GetType()).Cast<int>().Where(f => (f & value) == f); 
    return setValues.Any() ? setValues.Max() : 0; 
} 

metoda zawiedzie, jeśli T nie jest typem enum, więc kontrola powinna być korzystnie przeprowadza się na początku metody. Ponadto nie będzie działać w przypadku wyliczenia o typie podstawowym większym niż int (tj. long).

2

Jest to metoda, z której korzystam. To daje enum tylną

var maxStatus = Item.Status.GetFlags().Max(); 

Output: maxStatus = Zakończono

public static class EnumExtensions { 

    /// <summary>Enumerates get flags in this collection.</summary> 
    /// 
    /// <param name="value">The value. 
    /// </param> 
    /// 
    /// <returns>An enumerator that allows foreach to be used to process get flags in this collection.</returns> 
    public static IEnumerable<T> GetFlags<T> (this T value) where T : struct { 
     return GetFlags (value, Enum.GetValues (value.GetType()).Cast<T>().ToArray()); 
    } 

    /// <summary>Enumerates get flags in this collection.</summary> 
    /// 
    /// <param name="value"> The value. 
    /// </param> 
    /// <param name="values">The values. 
    /// </param> 
    /// 
    /// <returns>An enumerator that allows foreach to be used to process get flags in this collection.</returns> 
    private static IEnumerable<T> GetFlags<T> (T value, T [] values) where T : struct { 
     if (!typeof (T).IsEnum) { 
      throw new ArgumentException ("Type must be an enum."); 
     } 
     ulong bits = Convert.ToUInt64 (value); 
     var results = new List<T>(); 
     for (int i = values.Length - 1; i >= 0; i--) { 
      ulong mask = Convert.ToUInt64 (values [i]); 
      if (i == 0 && mask == 0L) 
       break; 
      if ((bits & mask) == mask) { 
       results.Add (values [i]); 
       bits -= mask; 
      } 
     } 
     if (bits != 0L) 
      return Enumerable.Empty<T>(); 
     if (Convert.ToUInt64 (value) != 0L) 
      return results.Reverse<T>(); 
     if (bits == Convert.ToUInt64 (value) && values.Length > 0 && Convert.ToUInt64 (values [0]) == 0L) 
      return values.Take (1); 
     return Enumerable.Empty<T>(); 
    } 
} 
0

Jak można rzucać w tę iz powrotem na uint, można użyć:

public uint LowestBit(uint x) 
{ 
    return ~(x&x-1)&x; 
} 
public uint HighestBit(uint x) 
{ 
    uint last = x; 
    while (x!=0) 
    { 
     last=x; 
     x&=x-1; 
    } 
    return last; 
} 
Powiązane problemy