如何比较 C # 中的标志?

下面是一个国旗枚举。

[Flags]
public enum FlagTest
{
None = 0x0,
Flag1 = 0x1,
Flag2 = 0x2,
Flag3 = 0x4
}

我不能让 if 语句计算为 true。

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;


if (testItem == FlagTest.Flag1)
{
// Do something,
// however This is never true.
}

我怎么才能让这一切成真呢?

90613 次浏览

对于位操作,需要使用位运算符。

这应该会奏效:

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do something,
// however This is never true.
}

编辑: 修正了我的 if 检查-我回到了我的 C/C + + 方式(感谢 Ryan Farley 指出)

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do something
}

(testItem & FlagTest.Flag1)是一个按位 AND 操作。

FlagTest.Flag1等价于带有 OP 枚举的 001。现在让我们假设 testItem有 Flag1和 Flag2(所以它是按位的 101) :

  001
&101
----
001 == FlagTest.Flag1
if((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
...
}

试试这个:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// do something
}
Basically, your code is asking if having both flags set is the same as having one flag set, which is obviously false. The code above will leave only the Flag1 bit set if it is set at all, then compares this result to Flag1.

我为此设置了一个扩展方法: 相关问题

基本上:

public static bool IsSet( this Enum input, Enum matchTo )
{
return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}

然后你可以做:

FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;


if( testItem.IsSet ( FlagTests.Flag1 ) )
//Flag1 is set

顺便说一下,我对枚举使用的约定是标准的单数,标志的复数。这样,您就可以从枚举名称中知道它是否可以保存多个值。

关于编辑。你不能让它成真。我建议您将所需的内容封装到另一个类(或扩展方法)中,以便更接近所需的语法。

也就是说。

public class FlagTestCompare
{
public static bool Compare(this FlagTest myFlag, FlagTest condition)
{
return ((myFlag & condition) == condition);
}
}

在.NET 4中有一个新的方法 Enum HasFlag,它允许你写:

if ( testItem.HasFlag( FlagTest.Flag1 ) )
{
// Do Stuff
}

我的意思是,这样更容易读懂。

NET 源代码表明,这与接受的答案执行相同的逻辑:

public Boolean HasFlag(Enum flag) {
if (!this.GetType().IsEquivalentTo(flag.GetType())) {
throw new ArgumentException(
Environment.GetResourceString(
"Argument_EnumTypeDoesNotMatch",
flag.GetType(),
this.GetType()));
}


ulong uFlag = ToUInt64(flag.GetValue());
ulong uThis = ToUInt64(GetValue());
// test predicate
return ((uThis & uFlag) == uFlag);
}

对于那些难以想象公认的解决方案正在发生什么的人来说 (就是这个) ,

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do stuff.
}

testItem(根据问题)定义为,

testItem
= flag1 | flag2
= 001 | 010
= 011

然后,在 if 语句中,比较的左边是,

(testItem & flag1)
= (011 & 001)
= 001

以及完整的 if 语句(如果在 testItem中设置了 flag1,则计算结果为 true) ,

(testItem & flag1) == flag1
= (001) == 001
= true

还有一条建议... ... 永远不要对值为“0”的标志执行标准的二进制检查。你对这面旗帜的检查将永远是正确的。

[Flags]
public enum LevelOfDetail
{
[EnumMember(Value = "FullInfo")]
FullInfo=0,
[EnumMember(Value = "BusinessData")]
BusinessData=1
}

如果根据 FullInfo 对输入参数进行二进制检查,则会得到:

detailLevel = LevelOfDetail.BusinessData;
bool bPRez = (detailLevel & LevelOfDetail.FullInfo) == LevelOfDetail.FullInfo;

BPrez 将永远是真的,因为任何东西 & 0总是 = = 0。


相反,您应该简单地检查输入的值是否为0:

bool bPRez = (detailLevel == LevelOfDetail.FullInfo);

@ Phil-Devaney

请注意,除了在最简单的情况下,与手动编写代码相比,Enum HasFlag会带来严重的性能损失。考虑以下代码:

[Flags]
public enum TestFlags
{
One = 1,
Two = 2,
Three = 4,
Four = 8,
Five = 16,
Six = 32,
Seven = 64,
Eight = 128,
Nine = 256,
Ten = 512
}




class Program
{
static void Main(string[] args)
{
TestFlags f = TestFlags.Five; /* or any other enum */
bool result = false;


Stopwatch s = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
result |= f.HasFlag(TestFlags.Three);
}
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds); // *4793 ms*


s.Restart();
for (int i = 0; i < 10000000; i++)
{
result |= (f & TestFlags.Three) != 0;
}
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds); // *27 ms*


Console.ReadLine();
}
}

HasFlags 扩展方法的迭代次数超过1000万次,需要4793毫秒,而标准的按位实现只需要27毫秒。

即使没有旗帜,你也可以使用这样的东西

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=0){
//..
}

或者如果您有一个零值枚举

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}