C# 查找枚举值中的最高集合标志
我使用带有flags属性的枚举作为跟踪状态的方法 一个例子如下: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
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;
}