Testing for bitwise Enum values

Is my understanding of a logical comparison correct given my example above?

Yes, logical in this context means the equality and inequality operators.

Is the way I am performing a bitwise comparison correct?

Yes, but there is an easier way: Enum.HasFlag. For example:

tct.HasFlag(TrainingComponentTypes.Qualification)

instead of:

(tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification

What is the right way to handle the "All" value (bitwise or logical). I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes. I can't see why we would, but then, you never know?

I think it is better to define All in the enum itself as the bitwise OR of all its parts. But you'll see people do it both ways.

Am I right in assuming that switch statements basically shouldn't be used for bitwise enums (given none is appears to be a special case and requires a logical comparison)?

No, not at all. Feel free to use them is switch statements. The case values must be constants but they can be expressions and are tested for equality. The compiler will tell you if you do something silly like try to use the same case value twice.


Short answer: Yes :)

Longer:

1) All operations are performed on the integer value of the flags variable, so you can think about them in terms of this.

2) Yes.

3) Either works. However, it's worth noting that if someone shoves an invalid value into a variable then the == TrainingComponentTypes.All version will fail. For example:

var badValue = (TrainingComponentTypes)128 | TrainingComponentTypes.All;
// now badValue != TrainingComponentTypes.All
// but (badValue & TrainingComponentTypes.All) == TrainingComponentTypes.All

For this part:

I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes.

I'm not sure you fully understand how the enum works under the covers.

The value of All is:
    127 = 1111111 (binary)

The other values are:
    AccreditedCourse       = 0000001
    Qualification          = 0000010
    Unit                   = 0000100
    SkillSet               = 0001000
    UnitContextualisation  = 0010000
    TrainingPackage        = 0100000
    AccreditedCourseModule = 1000000

As you can see, All is simply the bitwise | of all these values together. You can't combine any other TraningComponentTypes with All, because All already includes them! Also, if you combine them all together with | yourself it's exactly the same as using All directly (so, All is simply a convenience when you define it inside an enum).

4) You could use it to check for None or All but not for other values.

It's worth noting that there is a convenience method on Enum that will do these checks for you: Enum.HasFlag.