0

I have a Flags enum and want to assert that a given instance of it, is one of the primitive values, i.e. it has exactly one '1' in its binary representation, i.e. it's a power of two.

What's the best way to check this?

(I suppose "best" isn't necessarily well-defined, so ...)

  • What's the fastest way to check this?
  • What's the most semantically clear way to check this?
  • How do I check this, whilst writing the least code?
Brondahl
  • 7,402
  • 5
  • 45
  • 74
  • I was going to link the [bit twiddling hack](http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2), but I'm delighted to see the linked question already has an answer for it. I'd say this is close enough to count as a dupe. – Jeroen Mostert May 29 '19 at 13:15
  • @JeroenMostert I disagree that this should be closed as a dupe. I think that "the best way to do it is to cast to an int, and do the check against that" is a good answer, but there are plenty of other ways to do it, which might be very different. For example "there's an Enum API method that does that for you, which you didn't know about" would be a great answer, but not related to that linked answer – Brondahl May 29 '19 at 13:15
  • Alrighty then. I'm pretty sure the linked question has everything you could possibly want to write an answer that pleases you, though -- at least where the "fastest" and "least code" boxes are ticked; "semantically clear" is subjective, but (in my opinion) just one appropriate method name away from the smallest solutions. – Jeroen Mostert May 29 '19 at 13:17
  • I agree. I think that's highly likely to be the case - I just don't think that "the best solution is to make this change, and then the problem reduces down to a known solved problem", is the same as "this is a duplicate question". Very happy for the community to disagree, of course :) – Brondahl May 29 '19 at 13:20
  • Well, I can see the case for a more thorough discussion. To wit, testing for power-of-twoness is *not* the exact same as testing if a value is one of its *defined* flags, even though you cast the issue that way. Every enum can legally contain any integer value, but not all bits necessarily have flags assigned. (And some, arguably ill-defined flag enums may have "convenience tags" for combinations of flags, which would not be "primitive".) – Jeroen Mostert May 29 '19 at 13:24
  • If this test is necessary then making it [Flags] was a mistake. You'd then always favor sequential values, no checking required. – Hans Passant May 29 '19 at 13:32
  • Consider `[Flags] enum X { A = 1, B = 2, AandB = 1 + 2 }`; what should the test yield for `1`, `3`, and `4`, respectively? Arguably `true`, `false` and `false`, but neither the simple bit twiddling hack nor `Enum.IsDefined` will yield that. It'll be a balance between what assumptions you're allowed to make, why you're testing this in the first place, how generic it has to be and what kind of performance you need. Anything that actually needs the definition of the enum will likely involve some costly reflection that you'd want to cache in advance if testing for it many times. – Jeroen Mostert May 29 '19 at 13:38

2 Answers2

3

bit operation will yield the fastest result

((anInstanceOfTheFlaggedEnum & (anInstanceOfTheFlaggedEnum -1)) != 0)

over the more readable built in function

Enum.IsDefined(typeof(yourFlaggedEnumType), anInstanceOfTheFlaggedEnum)

I just ran a test and it was ~175 times faster..

TheDude
  • 257
  • 1
  • 9
  • Thanks. I was not aware of the Enum.IsDefined method. – Fabian May 29 '19 at 13:23
  • @Fabian still the bit operation is much faster.. for what he wanted – TheDude May 29 '19 at 13:28
  • The question was not only for the fastest one. – Fabian May 29 '19 at 13:45
  • The first test is exactly the opposite of what it should be (`==`). Even after fixing that, it will also yield `true` for `0` (no flags set) as well as any solitary bits that aren't flags in the enum, but whether those things are something you want or not will vary by scenario. – Jeroen Mostert May 29 '19 at 13:48
0

Using Framework functionality and be more flexible concerning the number of set flags one could use something like:

[Flags] 
public enum FlagsEnum {
   None = 0,
   One = 1,
   Two = 2,
   Three = 4,
}

void Main()
{
    var flags = FlagsEnum.Two;
    var hasOneElement = Enum.GetValues(typeof(FlagsEnum)).OfType<FlagsEnum>().Where(i => i != FlagsEnum.None && flags.HasFlag(i)).Count() == 1;
}
Fabian
  • 1,100
  • 11
  • 14