在枚举值中查找最高的标志位

8
我正在使用带有标记属性的枚举作为跟踪状态的一种方式。
以下是一个例子:
Created = 1
Completed = 2
Dispatched = 4

我希望能够找到已经设置的最高标志,而不需要编写过于死板的代码(如果检查这个,则执行那个操作,如果检查那个,则执行此操作)。例如,在这个例子中:

Item.Status = Status.Created | Status.Completed

神话般的方法将返回2 - 因为已完成的标志设置了最高值。
GetMaxSetFlagValue(Item.Status) // returns 2

我发现这些问题都围绕着实际枚举类型展开,而不是使用标志位的值。我相当肯定这可以用Linq来实现...?
3个回答

10

以下类似的代码应该可以工作:

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

如果T不是枚举类型,该方法将失败,因此最好在方法开始时执行检查。此外,对于基础类型大于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> ();
    }
}

1

由于您可以在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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接