17

I am trying out the new HasFlags features, and was wondering if the following should work:

enum.HasFlag(AccessRights.Read | AccessRights.Write)

... because it doesn't seem to...

 DBAccessRights rights = (DBAccessRights)permission.PermissionFlags;
  if (rights.HasFlag(DBAccessRights.WikiMode))
  {
     // works
  }


  if (rights.HasFlag(DBAccessRights.WikiMode | DBAccessRights.CreateNew))
  {
     // Doesn't work    
  }

  DBAccessRights flags = DBAccessRights.WikiMode | DBAccessRights.CreateNew;
  if (rights.HasFlag(flags))
  {
     // Doesn't work
  }
makerofthings7
  • 60,103
  • 53
  • 215
  • 448

5 Answers5

39

Given the documentation, I'd expect that to return true if the value has both of those flags.

If you want it to test whether your value has either of those flags, you'll need

value.HasFlag(AccessRights.Read) | value.HasFlag(AccessRights.Write)

If that's not good readable enough for you, you may want to look at my Unconstrained Melody project. It so happens that that already has the functionality you want (as extension methods in Flags.cs):

// Same as value.HasFlag(AccessRights.Read | AccessRights.Write)
value.HasAll(AccessRights.Read | AccessRights.Write)

// Same as value.HasFlag(AccessRights.Read) | value.HasFlag(AccessRights.Write)
value.HasAny(AccessRights.Read | AccessRights.Write)

Those would make it clearer, IMO. They'd also avoid boxing, and be typesafe :)

KyleMit
  • 30,350
  • 66
  • 462
  • 664
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Does boxing explain the performance note at the bottom of the documentation? – makerofthings7 Nov 02 '11 at 17:20
  • 1
    @makerofthings7: Maybe - it's hard to say for sure. It'd be interesting to measure the difference in performance between the framework and my implementation :) – Jon Skeet Nov 02 '11 at 17:27
  • @LamonteCristo This method must also do a type check before the unboxing. They want to throw an `ArgumentException` if you pass a reference of a wrong type. I wonder if the type check is done again during unboxing. We can check the bytecode or the C# source. – Jeppe Stig Nielsen Apr 19 '15 at 09:14
  • 1
    For Any, why would you not just do (AccessRights.Read | AccessRights.Write).HasFlag(value) ? – Novaterata Sep 24 '15 at 21:40
  • @JonSkeet I kind of love this. I want to write a few extensions of my own using this code, so I sort of shamelessly ripped your source code off GitHub. I left a text-file in my source code sourcing you and giving you credit though, so I hope you're not mad. – Will May 18 '17 at 02:49
  • @Will: How could I possibly be mad? It's open source - that's the point :) Glad it's useful! – Jon Skeet May 18 '17 at 03:43
  • 1
    Just incase anyone wants a direct link to the file that contains the `HasAll()` method `https://github.com/jskeet/unconstrained-melody/blob/master/UnconstrainedMelody/Flags.cs`. – Arvo Bowen Oct 11 '17 at 16:54
20

From MSDN:

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

thisInstance And flag = flag

For a complex flag such as AccessRights.Read | AccessRights.Write, this will check that all the "contained" flags are present.

You probably want to check that any of the flags are present, in which case you can do:

myAccessRights & (AccessRights.Read | AccessRights.Write) != 0 
Ani
  • 111,048
  • 26
  • 262
  • 307
  • Well I'm torn between accepting this vs Jon Skeet's answer. It's the performance optimal way of achieving my goal. His answer explains what I did wrong. – makerofthings7 Nov 02 '11 at 17:21
3

The | operator is bitwise or. It means that if Read is 1 and Write is 2, the value Read | Write is 3 (see its binary representation). So HasFlag returns true only if your enum variable have both Read and Write set.

NOtherDev
  • 9,542
  • 2
  • 36
  • 47
1

Alternatively, you could just reverse the order of the expression:

//returns true - a bit easier on the eye
(AccessRights.Read | AccessRights.Write).HasFlag(myAccessRights)

This will return true if you have either Read | Write access. That would be functionally equivalent to:

//also returns true - as per @Ani's answer
myAccessRights & (AccessRights.Read | AccessRights.Write) != 0

EDIT

As pointed out in the comments, The first expression will return true if myAccessRights is empty, and false if myAccessRights has more than just Read and Write.

AaronHS
  • 1,334
  • 12
  • 29
  • It returns true if myAccessRights has no flag set what is not right. But anyway. Like this approach – AnzeR Dec 22 '15 at 14:12
  • 1
    It is not functionally equivalent unless you are assuming that Read and Write are the only flags defined in AccessRights - which you shouldn't even if it is true. The first expression will return false if myAccessRights has any flags set other than read or write. – tordal Apr 28 '16 at 16:52
1

In a flagged enum you could simply do:

(MyEnum01 & MyEnum02) != 0

If there are any common bits, a bit will be set and thus the number is no longer 0. If there are no common bits, the result is 0. For that the flagged enum for 0 should represent "none".

Here is a static method for generic enums and one for a specific one:

public static partial class UtilityMethods
{
    public static bool HasAnyFlags (Enum enumA, Enum enumB)
    {
        return ((int) (object) enumA & (int) (object) enumB) != 0;
    }

    public static bool HasAnyFlags (MyEnum enumA, MyEnum enumB)
    {
        return (enumA & enumB) != 0;
    }
}

You could also create your own extension method:

public static partial class ExtensionMethods
{
    public static bool HasAnyFlag (this Enum e, Enum compared)
    {
        return ((int) (object) e & (int) (object) compared) != 0;
    }
}

For the generic enums I took the conversion from here. Allegedly it's more performant to do it with boxing rather than Converter.ToInt32().

Battle
  • 786
  • 10
  • 17