Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicitly defining flag combinations in an enum

I was thinking of implementing an enum that defines the state of a game object, and I wanted to know if I could directly use flags within the enum's definition, instead of defining the object's state as a collection of flags with no easy, pre-defined, global name for the states used in the state machine.

For example, let's say there are 5 states: PreActivation (Created but not started; i.e. an enemy in a future wave), Active (Currently in use; i.e. an enemy on the screen, attacking you), Paused (No longer active, but may reactivate; i.e. an enemy if the player uses a time-freezing power), DeActivated (An object whose finished use but is still in the game world; i.e. an enemy whose body is left after death like in Doom 1 & 2), and ToRemove (An object slated for removal from the game; i.e. an enemy after you clear a level and move to the next one).

What I want to do is define the enum so the states hold all applicable flags; for instance, a DeActivated enemy: 1. Has been previously activated, and 2. Isn't currently active. My current thinking is doing something like this:

public enum ObjectState
{
    // The first section are the flags
    BeenActivated   = 0b0000001, // Previously activated
    CurrentlyActive = 0b0000010, // Currently activated
    IsSuspended     = 0b0000100, // It may be reactivated
    ShouldRemove    = 0b0001000, // It should be removed
    // These are the states
    PreActivation   = 0b0000100, // Mot currently active, nor has it ever been active, but it will get activated
    Active          = 0b0000011, // Currently active,     and it's been active
    Paused          = 0b0000101, // Not currently active, but it's been active before
    DeActivated     = 0b0000001, // Not currently active, but it's been active before, and it shouldn't get reactivated, but don't remove yet
    ToRemove        = 0b0001001  // Not currently active, but it's been active before, and it shouldn't get reactivated, it should be removed
}

As far as I know, this should work correctly, but I have a few main concerns:

  1. Are there any problems likely to come from this?
  2. Is this bad practice?
  3. Is this bad practice? And, if it is;
    • A. What's wrong with it?
    • B. What should I do instead? I'd just make the object's state a collection of these flags, but I'd like a shorthand enum for specific states, as this allows for complexity for specific instances and simplicity when it's needed. Is there a more acceptable way to achieve this?

Sorry if this is a repeat or I broke some other rule, but I just created an account today; this is my 1st post. Plus, I'm not sure what you would call this when searching, and I didn't get any similar hits from here or Google.

like image 517
J Mor Avatar asked May 20 '18 20:05

J Mor


2 Answers

You can do so. It's the very point of flag enums. If an enum is intended to work as flags, mark it with the [Flags] attribute.

I would suggest to combine the existing flags with a bitwise or (|) instead. It's more readable and less error-prone.

[Flags]
public enum ObjectState
{
    // Flags
    BeenActivated   = 0b0000001, // Previously activated
    CurrentlyActive = 0b0000010, // Currently activated
    IsSuspended     = 0b0000100, // It may be reactivated
    ShouldRemove    = 0b0001000, // It should be removed

    // States as combination of flags.
    PreActivationState   = IsSuspended,                     // Mot currently active, nor has it ever been active, but it will get activated
    ActiveState          = BeenActivated | CurrentlyActive, // Currently active,     and it's been active
    PausedState          = BeenActivated | IsSuspended,     // Not currently active, but it's been active before
    DeActivatedState     = BeenActivated,                   // Not currently active, but it's been active before, and it shouldn't get reactivated, but don't remove yet
    ToRemoveState        = BeenActivated | ShouldRemove     // Not currently active, but it's been active before, and it shouldn't get reactivated, it should be removed
}

I also added a "State" suffix to the states to better differentiate them from flags. Or turn it around and add a "Flags" suffix to the flags instead.

like image 56
Olivier Jacot-Descombes Avatar answered Oct 06 '22 18:10

Olivier Jacot-Descombes


Did you consider using a [Flags]-enum?

[Flags]
public enum ObjectState
{
    BeenActivated   = 1, // Previously activated
    CurrentlyActive = 2, // Currently activated
    IsSuspended     = 4, // It may be reactivated
    ShouldRemove    = 8, // It should be removed
}

// Currently active, and it's been active
var active = ObjectState.BeenActivated | ObjectState.CurrentlyActive;
like image 43
Jan Köhler Avatar answered Oct 06 '22 18:10

Jan Köhler