2

I have this flag enumeration:

public enum AssignmentType
{
    None = 0,
    Attendant = 1,
    ConductorCBS = 2,
    ReaderCBS = 4,
    Chairman = 8,
    Mike = 16,
    PlatformAttendant = 32,
    Prayer = 64,
    OCLM = 128,
    Sound = 256,
    Student = 512,
    Custom = 1024,
    Demonstration = 2048,
    Assistant = 4096
}

I am now wanting to test my variable for a certain flag condition.

I want to identify my variable is only any combination of:

  • None
  • Student
  • Assistant
  • Demonstration

So if it has any of the other enumeration values the variable would not satisfy the test.

At first I started with this:

bool bIsPersonnel = true;

if (_Assignments == AssignmentType.None ||
    _Assignments == AssignmentType.Demonstration || 
    _Assignments == AssignmentType.Student ||
    _Assignments == AssignmentType.Assistant ||
    _Assignments == (AssignmentType.Demonstration | AssignmentType.Student))
{
    bIsPersonnel = false;
}

But I quickly realised the multiple choices there are.

Is there a simpler way?

I can't see how to suggested answer helps. I guess it is easiest to do my test in reverse. Just test if it has any of the other flags then I know it is personnel!

phuclv
  • 37,963
  • 15
  • 156
  • 475
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164

5 Answers5

6

You can apply a mask with the ~ bitwise negation operator to find all the invalid flags, and check whether any have been applied.

var valid = AssignmentType.Student | AssignmentType.Assistant | AssignmentType.Demonstration;
var invalid = ~valid; // Everything that isn't valid

if ((_Assignments & invalid) != 0)
{
    // There was at least one invalid flag, handle it appropriately
}

Or to check whether it's valid:

if ((_Assignment & invalid) == 0)
{
    // There are no invalid flags, handle it appropriately
}

Or if you're just after setting a single boolean flag, you don't need an if statement at all:

bool isPersonnel = ((assignment & invalid) != 0);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks. So this would equate to a simplified version of what I put in my proposed answer? – Andrew Truckle Mar 31 '19 at 09:14
  • 1
    Your code raises a syntax error about using `&` to compare `AssignmentType` and `bool`. – Andrew Truckle Mar 31 '19 at 09:17
  • 2
    I think you'll need to check for the `AssignmentType.None` state separately, because if `_Assignments == AssignmentType.None` then `(_Assignments & invalid != 0)` will be false (and the OP wants it to be true in that situation). – Matthew Watson Mar 31 '19 at 09:21
  • Please update your answer so that when I paste it into VC it does not raise a error. Thanks. – Andrew Truckle Mar 31 '19 at 11:39
  • 1
    @AndrewTruckle: Fixed with a pair of brackets. Should be fine now. – Jon Skeet Mar 31 '19 at 15:36
  • @MatthewWatson: I see no indication that the OP wants it to be true - the question says that it's *okay* to include `AssignmentType.None`, which is a good job, as any value "includes" 0. – Jon Skeet Mar 31 '19 at 15:37
2

(Incorrect answer)

if ((_Assignments & AssignmentType.None) > 0
    || (_Assignments & AssignmentType.Student) > 0
    || (_Assignments & AssignmentType.Assistant) > 0
    || (_Assignments & AssignmentType.Demonstration) > 0
){
    bIsPersonnel = false;
}

Corrected answer:

var NonPersonnel = AssignmentType.None | AssignmentType.Student | AssignmentType.Assistant | Demonstration;
bool bIsPersonnel = (_Assignments | NonPersonnel) != NonPersonnel;
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
2

I think this works as expected:

var flags =
    AssignmentType.None
    | AssignmentType.Student
    | AssignmentType.Assistant
    | AssignmentType.Demonstration;

bool bIsPersonnel =
    !(_Assignments == AssignmentType.None
        || (flags & _Assignments) == _Assignments);

Here is some sample output:

_Assignments = AssignmentType.Demonstration | AssignmentType.Assistant; // False
_Assignments = AssignmentType.None; // False
_Assignments = AssignmentType.Demonstration | AssignmentType.Mike; // True
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
0

At the moment I have come up with doing the reverse test:

bool bIsPersonnel = false;

if(_Assignments.HasFlag(AssignmentType.Attendant | AssignmentType.ConductorCBS |
    AssignmentType.ReaderCBS | AssignmentType.Chairman |
    AssignmentType.Mike | AssignmentType.PlatformAttendant |
    AssignmentType.Prayer | AssignmentType.OCLM |
    AssignmentType.Sound | AssignmentType.Custom))
{
    bIsPersonnel = true;
}

This is easiest because we know that if any one of those flags are set the person is "Personnel". The other flags are out of the picture and we don't have to test for multiple flag configurations.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
0

Just make a mask of values to check and and the mask with the value, that's how flags are checked, regardless of only the number of flags

if (0 != _Assignments &
     (AssignmentType.Demonstration | AssignmentType.Student | AssignmentType.Assistant))

No need to check AssignmentType.None because it's not a flag itself, just a reserved value that's equal to 0, used for checking that none of the flag is set. If the combination contains both "no flag" and "some other flag" then it doesn't make sense, right? If you do need to check the "no flag" condition then check it separately

if (_Assignments == AssignmentType.None || (0 != _Assignments &
         (AssignmentType.Demonstration | AssignmentType.Student | AssignmentType.Assistant)))

That's also how Enum.HasFlag() checks the flags

public static void Main()
{
   DinnerItems myOrder = DinnerItems.Appetizer | DinnerItems.Entree |
                        DinnerItems.Beverage | DinnerItems.Dessert;
   DinnerItems flagValue = DinnerItems.Entree | DinnerItems.Beverage;
   Console.WriteLine("{0} includes {1}: {2}", 
                     myOrder, flagValue, myOrder.HasFlag(flagValue));
}
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • Thanks, but again you are missing the point that the **other** flags might be set. See my own answer that might explain it clearer. – Andrew Truckle Mar 31 '19 at 09:12
  • I don't get what you mean by "other flags might be set"? You're checking if the variable has any bits among the flags enabled, right? This one does exactly that, returning true if only at least one of the specified flags are set. How on earth is other bits related here? – phuclv Mar 31 '19 at 09:18
  • We are looking to to see if they **only** have the stated flags. So if they also have, say `Attendant` then they don't satisfy the condition. – Andrew Truckle Mar 31 '19 at 09:22
  • 1
    `Attendant` isn't among `Demonstration | Student | Assistant`, so if the Attendant isn't `Demonstration | Student | Assistant` obviously the condition is true, and `bIsPersonnel` will be false as expected – phuclv Mar 31 '19 at 09:25
  • OK, sorry! I easily get confused with flags. Thanks! – Andrew Truckle Mar 31 '19 at 09:34