如何比较 C# 中的标志?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40211/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Compare Flags in C#?
提问by David Basarab
I have a flag enum below.
我在下面有一个标志枚举。
[Flags]
public enum FlagTest
{
None = 0x0,
Flag1 = 0x1,
Flag2 = 0x2,
Flag3 = 0x4
}
I cannot make the if statement evaluate to true.
我不能让 if 语句评估为真。
FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;
if (testItem == FlagTest.Flag1)
{
// Do something,
// however This is never true.
}
How can I make this true?
我怎样才能做到这一点?
采纳答案by Phil Devaney
In .NET 4 there is a new method Enum.HasFlag. This allows you to write:
在 .NET 4 中有一个新方法Enum.HasFlag。这允许您编写:
if ( testItem.HasFlag( FlagTest.Flag1 ) )
{
// Do Stuff
}
which is much more readable, IMO.
这更具可读性,IMO。
The .NET source indicates that this performs the same logic as the accepted answer:
.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);
}
回答by 17 of 26
For bit operations, you need to use bitwise operators.
对于位操作,您需要使用按位运算符。
This should do the trick:
这应该可以解决问题:
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do something,
// however This is never true.
}
Edit:Fixed my if check - I slipped back into my C/C++ ways (thanks to Ryan Farley for pointing it out)
编辑:修复了我的 if 检查 - 我回到了我的 C/C++ 方式(感谢 Ryan Farley 指出)
回答by Scott Nichols
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do something
}
(testItem & FlagTest.Flag1)
is a bitwise AND operation.
(testItem & FlagTest.Flag1)
是按位与运算。
FlagTest.Flag1
is equivalent to 001
with OP's enum. Now let's say testItem
has Flag1 and Flag2 (so it's bitwise 101
):
FlagTest.Flag1
相当于001
与 OP 的枚举。现在让我们说testItem
有 Flag1 和 Flag2 (所以它是按位的101
):
001
&101
----
001 == FlagTest.Flag1
回答by Damian
if((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
...
}
回答by OwenP
Try this:
尝试这个:
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// do something
}
基本上,您的代码询问设置两个标志是否与设置一个标志相同,这显然是错误的。如果设置了 Flag1 位,上面的代码将只保留 Flag1 位,然后将此结果与 Flag1 进行比较。回答by Keith
I set up an extension method to do it: related question.
我设置了一个扩展方法来做到这一点:相关问题。
Basically:
基本上:
public static bool IsSet( this Enum input, Enum matchTo )
{
return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}
Then you can do:
然后你可以这样做:
FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;
if( testItem.IsSet ( FlagTests.Flag1 ) )
//Flag1 is set
Incidentally the convention I use for enums is singular for standard, plural for flags. That way you know from the enum name whether it can hold multiple values.
顺便说一句,我用于枚举的约定对于标准来说是单数,对于标志来说是复数。这样你就可以从枚举名称中知道它是否可以容纳多个值。
回答by Martin Clarke
Regarding the edit. You can't make it true. I suggest you wrap what you want into another class (or extension method) to get closer to the syntax you need.
关于编辑。你不能让它成真。我建议你把你想要的东西包装到另一个类(或扩展方法)中,以更接近你需要的语法。
i.e.
IE
public class FlagTestCompare
{
public static bool Compare(this FlagTest myFlag, FlagTest condition)
{
return ((myFlag & condition) == condition);
}
}
回答by Sekhat
For those who have trouble visualizing what is happening with the accepted solution (which is this),
对于那些难以想象接受的解决方案(就是这个)发生了什么的人,
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
// Do stuff.
}
testItem
(as per the question) is defined as,
testItem
(根据问题)被定义为,
testItem
= flag1 | flag2
= 001 | 010
= 011
Then, in the if statement, the left hand side of the comparison is,
然后,在 if 语句中,比较的左侧是,
(testItem & flag1)
= (011 & 001)
= 001
And the full if statement (that evaluates to true if flag1
is set in testItem
),
以及完整的 if 语句(如果flag1
在 中设置,则计算结果为真testItem
),
(testItem & flag1) == flag1
= (001) == 001
= true
回答by Leonid
One more piece of advice... Never do the standard binary check with the flag whose value is "0". Your check on this flag will always be true.
还有一条建议......永远不要对值为“0”的标志进行标准二进制检查。您对此标志的检查将始终为真。
[Flags]
public enum LevelOfDetail
{
[EnumMember(Value = "FullInfo")]
FullInfo=0,
[EnumMember(Value = "BusinessData")]
BusinessData=1
}
If you binary check input parameter against FullInfo - you get:
如果您针对 FullInfo 对输入参数进行二进制检查 - 您会得到:
detailLevel = LevelOfDetail.BusinessData;
bool bPRez = (detailLevel & LevelOfDetail.FullInfo) == LevelOfDetail.FullInfo;
bPRez will always be true as ANYTHING & 0 always == 0.
bPRez 将始终为真,因为 ANYTHING & 0 始终 == 0。
Instead you should simply check that the value of the input is 0:
相反,您应该简单地检查输入的值是否为 0:
bool bPRez = (detailLevel == LevelOfDetail.FullInfo);
回答by Chuck Dee
@phil-devaney
@菲尔德瓦尼
Note that except in the simplest of cases, the Enum.HasFlagcarries a heavy performance penalty in comparison to writing out the code manually. Consider the following code:
请注意,除了在最简单的情况下,与手动编写代码相比,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();
}
}
Over 10 million iterations, the HasFlags extension method takes a whopping 4793 ms, compared to the 27 ms for the standard bitwise implementation.
超过 1000 万次迭代,HasFlags 扩展方法需要惊人的 4793 毫秒,而标准按位实现需要 27 毫秒。