简体   繁体   English

在枚举值中找到最高的设置标志

[英]Finding the highest set flag in an enum value

I'm using a enum with flags attribute as a way of tracking status. 我使用带有flags属性的枚举作为跟踪状态的一种方式。

An example is the following: 下面是一个示例:

Created = 1
Completed = 2
Dispatched = 4

Without writing anything too rigid (if check this, do that, if check that, do this) i want to be able to find the highest flag which has been set so in this example: 在不编写任何过于严格的内容的情况下(如果要进行检查,请执行此操作,如果要进行检查,请执行此操作),我希望能够找到已设置的最高标志,因此在此示例中:

Item.Status = Status.Created | Status.Completed

the mythical method would return 2 - as completed is the flag set with the highest value. 神话方法将返回2-完成时,将标志设置为最高值。

GetMaxSetFlagValue(Item.Status) // returns 2

I've found questions which revolved around the actual enum, just not a value which uses flags. 我发现了围绕实际枚举的问题,而不是使用标志的值。 I'm fairly sure this could be achieved with Linq...? 我相当确定可以使用Linq来实现...?

Something like the following should work: 类似于以下内容的东西应该起作用:

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

The method will fail if T is not an enum type, so a check should preferably be performed in the beginning of the method. 如果T不是枚举类型,则该方法将失败,因此最好在该方法的开头执行检查。 Also it will not work for an enum with an underlying type larger than int (ie long ). 同样,它对于基本类型大于int (即long )的枚举也不起作用。

This is the extension method I use. 这是我使用的扩展方法。 It will give you the enum back 它将给您枚举

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

Output: maxStatus = Completed 输出: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> ();
    }
}

As you can cast back and forth to uint, you could use: 由于可以前后转换为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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM