Question

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.

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

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

How can I make this true?

Was it helpful?

Solution

In .NET 4 there is a new method Enum.HasFlag. This allows you to write:

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

which is much more readable, IMO.

The .NET source indicates that this performs the same logic as the accepted answer:

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); 
}

OTHER TIPS

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

(testItem & FlagTest.Flag1) is a bitwise AND operation.

FlagTest.Flag1 is equivalent to 001 with OP's enum. Now let's say testItem has Flag1 and Flag2 (so it's bitwise 101):

  001
 &101
 ----
  001 == FlagTest.Flag1

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 
 = flag1 | flag2  
 = 001 | 010  
 = 011

Then, in the if statement, the left hand side of the comparison is,

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

And the full if statement (that evaluates to true if flag1 is set in testItem),

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

@phil-devaney

Note that except in the simplest of cases, the Enum.HasFlag carries a heavy performance penalty in comparison to writing out the code manually. Consider the following code:

[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.

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.

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.

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

If you binary check input parameter against FullInfo - you get:

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

bPRez will always be true as ANYTHING & 0 always == 0.


Instead you should simply check that the value of the input is 0:

bool bPRez = (detailLevel == LevelOfDetail.FullInfo);
if((testItem & FlagTest.Flag1) == FlagTest.Flag1) 
{
...
}

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)

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.

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

Try this:


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.

even without [Flags], you could use something like this

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

or if you have a Zero value enum

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top