20

If I have enum

    [Flags]
    public enum GameFlow
    {
        Normal = 1,
        NormalNoMove = 2,
        Paused = 4,
        Battle = 8
    }

Is it possible to check if the enum is in either one of desired states with a single check? For example if I'd like to check if enum's is either Normal or NormalNoMove do I always have to write it like this?

if(Flow == GameFlow.Normal || Flow == GameFlow.NormalNoMove)

It's not a big problem if there are only two values but there will be more enum states and it would be nice if I only would have to change it in one place. Is it somehow possible to make an enum alias that would return true if enum value is either Normal or NormalNoMove? Or do I have to write some kind of helper method to achive that(extension method?)

kasztelan
  • 1,731
  • 3
  • 17
  • 24

6 Answers6

26

Maybe it can be useful

public static class EnumExtensions
{
    public static bool IsOneOf(this Enum enumeration, params Enum[] enums)
    {
        return enums.Contains(enumeration);
    }
}

// usage:
if(Flow.IsOneOf(GameFlow.Normal, GameFlow.NormalNoMove))
DCharodey
  • 269
  • 3
  • 5
18

Bitwise logic should work on flag enums like this.

if((Flow & (GameFlow.Normal | GameFlow.NormalNoMove)) > 0)

It's also possible to create enum values that combine other values, as I mention here.

So, in your case:

[Flags]
public enum GameFlow
{
    Normal = 1,
    NormalNoMove = 2,
    Paused = 4,
    Battle = 8,
    AnyNormal = Normal | NormalNoMove
}

bool IsNormal(GameFlow flow)
{
    return (flow & GameFlow.AnyNormal) > 0;
}

And a LINQPad test:

void Main()
{
    IsNormal(GameFlow.Normal).Dump();// True
    IsNormal(GameFlow.NormalNoMove).Dump();// True
    IsNormal(GameFlow.Paused).Dump();// False
    IsNormal(GameFlow.Battle).Dump();// False

    IsNormal(GameFlow.Normal | GameFlow.Paused).Dump();// True
    IsNormal(GameFlow.NormalNoMove  | GameFlow.Battle).Dump();// True
    IsNormal(GameFlow.Paused | GameFlow.Battle).Dump();// False
    IsNormal(GameFlow.Battle | GameFlow.Normal).Dump();// True

}

Based on your comment, I'm wondering if you should revise the bitwise flags here, too. It sounds like "Normal" is a state you want to check for, and "NormalNoMove" builds on that. Maybe your enum should look more like this:

[Flags]
public enum GameFlow
{
    Normal = 1,
    NormalNoMove = Normal | 2,
    Paused = 4,
    Battle = 8
}

That way, you can check whether flow & GameFlow.Normal > 0 to see if you're in either normal state: NormalNoMove just "extends" Normal, so to speak.

Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • Yes, I know that but still I have to explicitly use Normal and NormalNoMove in every place I'm doing condition check. I was hoping there was a way to create another enum state, for example NormalState that would return true in condition check if value was either Normal or NormalNoMove – kasztelan Aug 01 '13 at 18:08
  • @kasztelan: I expanded my answer to address your comment. – StriplingWarrior Aug 01 '13 at 18:13
  • Thank you! `(flow & GameFlow.AnyNormal) > 0;` is the answer I was looking for. This way if I ever want to extend AnyNormal with a third state I'll have to just change its declaration in the enum. Perfect! – kasztelan Aug 01 '13 at 18:17
  • @kasztelan: If "NormalNoMove" is just an extension of the "Normal" state, you may want to declare it differently. See my update. – StriplingWarrior Aug 01 '13 at 18:20
  • Can you not simply do <= NormalNoMove in this instance? – ChrisFox Aug 01 '16 at 10:40
  • 3
    @ChrisFox: You could, but to understand why that works you'd have to know specific value information about the enum values. A new developer coming in would need to go look at the enum's implementation details to understand the intent of your code, whereas anyone who understands flag enums would read `(flow & GameFlow.Normal) > 0` and say "oh, they want to know if the `GameFlow.Normal` flag is active. – StriplingWarrior Aug 01 '16 at 14:52
11

As per C# 9 I would write expressions like that using pattern matching. In this case.

if(Flow is GameFlow.Normal or GameFlow.NormalNoMove) 
{
   // your code...
}
4

Based on a comment to @StringlingWarrior's answer, you could just create an extension method that will shorten your code:

public static class GameFlowExtensions
{
    public static bool IsNormal(this GameFlow flow)
    {
        return (flow & (GameFlow.Normal | GameFlow.NormalNoMove)) > 0;
    }
}

// usage:
if (Flow.IsNormal()) 
Austin Salonen
  • 49,173
  • 15
  • 109
  • 139
  • Thank you but fortunately I don't have to create extension method, the `(flow & GameFlow.AnyNormal) > 0;` part was exatly what I was looking for – kasztelan Aug 01 '13 at 18:18
1

You could set a variable to be equal to GameFlow.Normal and GameFlow.NormalNoMove and then compare the value you have to it, as so:

GameFlow NormalOrNormalNoMove = GameFlow.Normal | GameFlow.NormalNoMove;
...
if ((Flow & NormalOrNormalNoMove) > 0)
{
    // Your code
}
Martin
  • 16,093
  • 1
  • 29
  • 48
0
var requiredFlows = new [] {
    GameFlow.NormalNoMove,
    GameFlow.Normal,
    // Other values of the GameFlow enum.
}.ToHashSet();

if (requiredFlows.Contains(currentFlow))
{
    // Your code.
}

Ideally, requiredFlows should be a private static readonly field.

Palindromer
  • 854
  • 1
  • 10
  • 29