我只想知道是否设置了一个枚举标志,而不是哪个。我目前的想法是检查它是否是2的幂。在枚举类型中是否有更好的方法?
[Flags]
enum Foo
{
Flag1 = 0x01,
Flag2 = 0x02,
Flag3 = 0x04,
Flag4 = 0x08,
Flag5 = 0x10,
Flag6 = 0x20,
Flag7 = 0x40,
Flag8 = 0x80
}
private bool ExactlynOneFlagSet(Foo myFoo)
{
var x = (byte) myFoo;
return (x != 0) && ((x & (x - 1)) == 0); //Check if a power of 2
}
if(!ExactlynOneFlagSet(Foo myFoo))
{
//Do something
}
答案 0 :(得分:60)
它的Bit操作!
if ((myFoo & (myFoo -1)) != 0) //has more than 1 flag
该语句检查myFoo
的值是否不是2的幂。或者,反之亦然,声明(myFoo & (myFoo -1)) == 0
检查2的幂。这个想法是只有单个标志值将是2的幂。设置多个标志将导致两个值为myFoo
的非幂。
在类似问题的答案中可以找到更多信息:https://stackoverflow.com/a/1662162/2404788。
有关位操作的更多信息,请转至http://en.wikipedia.org/wiki/Bitwise_operation
答案 1 :(得分:11)
private bool ExatlyOneFlagSet(Foo myFoo)
{
return !myFoo.ToString().Contains(',');
}
答案 2 :(得分:8)
如果枚举没有定义标记的显式组合,您只需检查该值是否在枚举中定义:
private bool ExactlynOneFlagSet(Foo myFoo)
{
return Enum.IsDefined(typeof(Foo), myFoo);
}
答案 3 :(得分:0)
雅各布在评论中解释说你的方法根本不正确。我个人总是避免数学编程,特别是在逻辑方面。所以我的解决方案就是“如果我想知道计数是一个,那就算一下,把它与第一个进行比较”。
这是:
public static bool OneIsSet(Type enumType, byte value)
{
return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1;
}
public static bool OneIsSet(Type enumType, int value)
{
return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1;
}
你可以将它用于你的foo类型:
var toReturnFalse = (byte)(foo.Flag1 | foo.Flag2);
var toReturnTrue = (byte)foo.Flag1;
var trueWillBeReturned = OneIsSet(typeof(foo), toReturnTrue);
var falseWillBeReturned = OneIsSet(typeof(foo), toReturnFalse);
我相信这些方法可以使用泛型和类型处理方法以更通用的方式编写。但是我为枚举的大多数常见基类型包括了int和byte的方法。但你也可以写短文和其他类型。 您也可以在代码中内联代码。它只有一行代码。
同样使用此方法,您可以查看设置标志的数量是否为两个或更多。如果set flags的计数等于'n',则下面的代码返回true。
Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == n;
答案 4 :(得分:0)
如果您使用的是.NET Core 3.0+,则可以使用PopCount,它返回uint
或ulong
中的“ 1”位数,并使用{{ 1}} CPU指令(如果CPU支持SSE4,否则它将使用软件后备)。
POPCNT
public static bool ExactlyOneFlagSet(Foo foo)
{
return BitOperations.PopCount((ulong)foo) == 1;
}