我在下面有一个标志枚举。
[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.
}
我怎样才能做到这一点?
答案 0 :(得分:308)
在.NET 4中有一种新方法Enum.HasFlag。这允许你写:
if ( testItem.HasFlag( FlagTest.Flag1 ) )
{
// Do Stuff
}
更易读,IMO。
.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);
}
答案 1 :(得分:175)
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
答案 2 :(得分:78)
对于那些无法直观显示已接受解决方案的内容的人 (就是这个),
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do stuff.
}
testItem
(根据问题)被定义为,
testItem
= flag1 | flag2
= 001 | 010
= 011
然后,在if语句中,比较的左侧是,
(testItem & flag1)
= (011 & 001)
= 001
完整的if语句(如果在flag1
中设置testItem
,则评估为true),
(testItem & flag1) == flag1
= (001) == 001
= true
答案 3 :(得分:24)
@菲尔-德瓦尼
请注意,除了最简单的情况外,与手动编写代码相比,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();
}
}
超过1000万次迭代,HasFlags扩展方法需要高达4793 ms,而标准按位实现则为27 ms。
答案 4 :(得分:21)
我设置了一个扩展方法:related question。
基本上:
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
顺便提一下,我用于枚举的惯例对于标准是单数,对于标志是复数。这样你就可以从枚举名称中知道它是否可以包含多个值。
答案 5 :(得分:19)
还有一条建议......永远不要使用值为“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将永远是真实的,因为任何&amp; 0总是== 0。
相反,您应该只检查输入的值是否为0:
bool bPRez = (detailLevel == LevelOfDetail.FullInfo);
答案 6 :(得分:7)
if((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
...
}
答案 7 :(得分:5)
对于位操作,您需要使用按位运算符。
这应该可以解决问题:
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do something,
// however This is never true.
}
编辑:修正了我的检查 - 我又回到了我的C / C ++方式(感谢Ryan Farley指出它)
答案 8 :(得分:5)
关于编辑。你无法做到这一点。我建议你将你想要的东西包装到另一个类(或扩展方法)中,以便更接近你需要的语法。
即。
public class FlagTestCompare
{
public static bool Compare(this FlagTest myFlag, FlagTest condition)
{
return ((myFlag & condition) == condition);
}
}
答案 9 :(得分:4)
试试这个:
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// do something
}
基本上,你的代码询问是否设置了两个标志与设置一个标志相同,这显然是错误的。如果设置完全,则上面的代码将仅保留Flag1位,然后将此结果与Flag1进行比较。
答案 10 :(得分:1)
即使没有[Flags],你也可以使用类似的东西
if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=0){
//..
}
或者如果您有零值枚举
if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}