Should "or" work with .Net4 Hasflags: enum.HasFlag(AccessRights.Read | AccessRights.Write)

11.8k Views Asked by At

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
  }
5

There are 5 best solutions below

7
On BEST ANSWER

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 :)

0
On

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.

1
On

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 
0
On

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().

2
On

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.