2011-10-16 60 views
7

我使用帶有flags屬性的枚舉作爲跟蹤狀態的一種方式。在枚舉值中查找最高設置標誌

一個例子如下:

Created = 1 
Completed = 2 
Dispatched = 4 

不寫任何東西太死板(如果檢查這,做那,如果檢查,做到這一點),我希望能夠找到這一直是最高的標誌在此示例中設置如下:

Item.Status = Status.Created | Status.Completed 

神話方法將返回2 - 因爲已完成是具有最高值的標誌。

GetMaxSetFlagValue(Item.Status) // returns 2 

我發現了圍繞實際枚舉的問題,只是沒有使用標誌的值。我相當肯定這可以通過Linq來實現......?

回答

7

類似以下應該工作:如果T是不是一個枚舉類型,所以檢查應優選在該方法的開始時進行

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

的方法將失敗。對於基本類型大於int的枚舉(即long),它也不起作用。

2

這是我使用的擴展方法。它會給你枚舉回

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

輸出:maxStatus =完成

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

正如你可以施放來回UINT,你可以使用:

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