34

This is the enum definition:

[Flags]
enum Animals
{
    None = 0,
    Dog = 1,
    Cat = 2,
    Horse = 4,
    Zebra = 8,
}

Now, given the following code, why does the HasFlag method return true for the value Animals.None?

Animals myAnimals = Animals.Dog | Animals.Horse;

var hasNone = myAnimals.HasFlag(Animals.None);    //true! Why?
var hasCat = myAnimals.HasFlag(Animals.Cat);      //false
var hasDog = myAnimals.HasFlag(Animals.Dog);      //true
var hasHorse = myAnimals.HasFlag(Animals.Horse);  //true
var hasZebra = myAnimals.HasFlag(Animals.Zebra);  //false
Henrik Söderlund
  • 4,286
  • 3
  • 26
  • 26

7 Answers7

48

HasFlag is effectively this:

HasFlag = (GivenFlag & Value) == GivenFlag;

//"Anything" AND 0 == 0  --> always true
Austin Salonen
  • 49,173
  • 15
  • 109
  • 139
11

I've come up against this before myself. It's by design in the .NET Framework:

If the underlying value of flag is zero, the method returns true. If this behavior is not desirable, you can use the Equals method to test for equality with zero and call HasFlag only if the underlying value of flag is non-zero, as the following example illustrates.

You can read a little more about this here.

gcode
  • 2,954
  • 4
  • 21
  • 32
Martin
  • 16,093
  • 1
  • 29
  • 48
  • To expand on this, the solution I've implemented is to handle the Zero edgecase by calling `value.Equals(myEnum.Zero)`, then every other case is handled by `.HasFlag`. – gcode Oct 11 '22 at 00:48
2

There is already a plethora of answers describing WHY this happens, so I will just add that what you can do to get what you're looking for is to not use HasFlag in that case, but instead do var hasNone = myAnimals == Animals.None.

I personally really loathe extension methods, but it would be possible to put this in an extension on Enum if you really value being able to just write myOptionEnum.HasNoFlags(). I would just run with explicitly checking for the None value in this special case though.

sara
  • 3,521
  • 14
  • 34
0

Well Enum.HasFlags resolves as something like the following:

var hasNone = (myAnimals & Animals.None) == Animals.None

This will always be true for a zero-value-enum-field.

TGlatzer
  • 5,815
  • 2
  • 25
  • 46
0

From MSDN

The HasFlag method returns the result of the following Boolean expression.

thisInstance And flag = flag
Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
0

This is just the defined behavior of the HasFlag method. From the MSDN documentation

if the underlying value of flag is zero, the method returns true

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
0

I ended up removing the 'None' element. It is a 'magic value' and interferes with proper Flags Enum operations (like HasFlag()).

If there is no value then use Nullable i.e. Animals? (which now supports primitive types)

EDIT: I needed a 'Default' value (that is non-zero) for use in a serializable object in order to avoid using Nullable (which conflicted with the business logic). But I think this is still better than using 'None=0'.

Peter L
  • 2,921
  • 1
  • 29
  • 31
  • Zero is the default value for any enum, so it's better to keep it in the enum. – Vladislav Borovikov Apr 29 '22 at 12:20
  • @VladislavBorovikov, having 'None=0' breaks HasFlag() logic. One can always test an enum for 0 just like testing an object for null. The approach I described is if you want HasFlag() to work every time. – Peter L Apr 29 '22 at 23:46