C# 查找枚举值中的最高集合标志

C# 查找枚举值中的最高集合标志,c#,.net,enums,C#,.net,Enums,我使用带有flags属性的枚举作为跟踪状态的方法 一个例子如下: Created = 1 Completed = 2 Dispatched = 4 在不写任何太死板的东西的情况下(如果勾选这个,那么做,如果勾选那个,那么做这个),我希望能够找到在本例中设置的最高标志: Item.Status = Status.Created | Status.Completed 神秘的方法将返回2-因为完成是具有最高值的标志集 GetMaxSetFlagValue(Item.Status) // retur

我使用带有flags属性的枚举作为跟踪状态的方法

一个例子如下:

Created = 1
Completed = 2
Dispatched = 4
在不写任何太死板的东西的情况下(如果勾选这个,那么做,如果勾选那个,那么做这个),我希望能够找到在本例中设置的最高标志:

Item.Status = Status.Created | Status.Completed
神秘的方法将返回2-因为完成是具有最高值的标志集

GetMaxSetFlagValue(Item.Status) // returns 2

我发现了围绕实际枚举的问题,而不是使用标志的值。我相当肯定这可以通过Linq实现…?

类似于以下的功能应该可以工作:

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;
}
static int GetMaxSetFlagValue(T标志),其中T:struct
{
int value=(int)Convert.ChangeType(标志,typeof(int));
IEnumerable setValues=Enum.GetValues(flags.GetType()).Cast()。其中(f=>(f&value)==f);
返回setValues.Any()?setValues.Max():0;
}

如果T不是枚举类型,则该方法将失败,因此最好在该方法的开头执行检查。此外,对于基础类型大于
int
(即
long
)的枚举,它也不起作用。

这是我使用的扩展方法。它将返回枚举

var maxStatus = Item.Status.GetFlags().Max();
输出:maxStatus=Completed

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> ();
    }
}
公共静态类枚举扩展{
///枚举此集合中的get标志。
///
///价值。
/// 
///
///允许使用foreach处理此集合中的get标志的枚举数。
公共静态IEnumerable GetFlags(此T值),其中T:struct{
返回GetFlags(value,Enum.GetValues(value.GetType()).Cast().ToArray());
}
///枚举此集合中的get标志。
///
///价值。
/// 
///价值观。
/// 
///
///允许使用foreach处理此集合中的get标志的枚举数。
私有静态IEnumerable GetFlags(T值,T[]值),其中T:struct{
if(!typeof(T).IsEnum){
抛出新ArgumentException(“类型必须是枚举”);
}
ulong位=Convert.ToUInt64(值);
var results=新列表();
对于(int i=values.Length-1;i>=0;i--){
ulong mask=Convert.ToUInt64(值[i]);
如果(i==0&&mask==0L)
打破
if((位和掩码)=掩码){
结果。添加(值[i]);
位-=掩码;
}
}
如果(位!=0L)
返回Enumerable.Empty();
如果(Convert.ToUInt64(值)!=0L)
返回结果;
如果(位==Convert.ToUInt64(值)&&values.Length>0&&Convert.ToUInt64(值[0])==0L)
返回值。取(1);
返回Enumerable.Empty();
}
}

由于您可以来回转换到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;
}