2011-10-16 32 views
7

Tôi đang sử dụng một enum với thuộc tính flags làm cách theo dõi trạng thái.Tìm cờ được đặt cao nhất trong một giá trị enum

Một ví dụ là như sau:

Created = 1 
Completed = 2 
Dispatched = 4 

Nếu không viết bất cứ điều gì quá cứng nhắc (nếu việc kiểm tra này, làm điều đó, nếu kiểm tra rằng, làm được điều này) tôi muốn để có thể tìm thấy những lá cờ cao nhất mà đã được đặt trong ví dụ này:

Item.Status = Status.Created | Status.Completed 

phương pháp thần thoại sẽ trả về 2 - khi hoàn thành là cờ được đặt có giá trị cao nhất.

GetMaxSetFlagValue(Item.Status) // returns 2 

Tôi đã tìm thấy câu hỏi xoay quanh enum thực tế, không phải là giá trị sử dụng cờ. Tôi khá chắc chắn điều này có thể đạt được với Linq ...?

Trả lời

7

giống như sau nên làm việc:

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

Phương pháp này sẽ thất bại nếu T không phải là một kiểu enum, do đó, một kiểm tra tốt nhất là nên được thực hiện vào đầu của phương pháp. Ngoài ra, nó sẽ không hoạt động cho một enum với một loại cơ bản lớn hơn int (ví dụ: long).

2

Đây là phương pháp tiện ích tôi sử dụng. Nó sẽ cung cấp cho bạn các enum lại

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

Output: maxStatus = Hoàn

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

Như bạn có thể bỏ qua lại để uint, bạn có thể sử dụng:

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; 
} 
Các vấn đề liên quan