【问题标题】:Check if enum is in one of desired states检查枚举是否处于所需状态之一
【发布时间】:2013-08-02 19:20:11
【问题描述】:

如果我有枚举

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

是否可以通过一次检查来检查枚举是否处于所需状态之一?例如,如果我想检查枚举是 Normal 还是 NormalNoMove,我总是必须这样写吗?

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

如果只有两个值,这不是一个大问题,但会有更多的枚举状态,如果我只需要在一个地方更改它会很好。如果枚举值是 Normal 或 NormalNoMove,是否可以创建一个返回 true 的枚举别名?还是我必须编写某种辅助方法来实现(扩展方法?)

【问题讨论】:

  • 我想 Flow 是 GameFlow 类型的?
  • 是的,是GameFlow类型的

标签: c# enums


【解决方案1】:

按位逻辑应该适用于这样的标志枚举。

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

还可以创建结合其他值的枚举值,正如我提到的here

所以,在你的情况下:

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

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

还有一个 LINQPad 测试:

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

}

根据您的评论,我想知道您是否也应该在这里修改按位标志。听起来“Normal”是您要检查的状态,而“NormalNoMove”就是在此基础上构建的。也许你的枚举应该看起来更像这样:

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

这样,您可以检查flow & GameFlow.Normal > 0 是否处于正常状态:NormalNoMove 只是“扩展”Normal,可以这么说。

【讨论】:

  • 是的,我知道,但我仍然必须在我进行条件检查的每个地方明确使用 Normal 和 NormalNoMove。我希望有一种方法可以创建另一个枚举状态,例如 NormalState 会在条件检查中返回 true,如果值是 Normal 或 NormalNoMove
  • @kasztelan:我扩展了我的答案以解决您的评论。
  • 谢谢! (flow & GameFlow.AnyNormal) > 0; 是我一直在寻找的答案。这样,如果我想用第三种状态扩展 AnyNormal,我将不得不更改它在枚举中的声明。完美!
  • @kasztelan:如果“NormalNoMove”只是“Normal”状态的扩展,您可能需要以不同的方式声明它。查看我的更新。
  • @ChrisFox:你可以,但要理解为什么会这样,你必须知道关于枚举值的具体值信息。新加入的开发人员需要查看枚举的实现细节以了解代码的意图,而任何了解标志枚举的人都会阅读 (flow & GameFlow.Normal) > 0 并说“哦,他们想知道 GameFlow.Normal 标志是否是活跃。
【解决方案2】:

根据@StringlingWarrior 的回答,您可以创建一个扩展方法来缩短您的代码:

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

// usage:
if (Flow.IsNormal()) 

【讨论】:

  • 谢谢,但幸运的是我不必创建扩展方法,(flow & GameFlow.AnyNormal) > 0; 部分正是我想要的
【解决方案3】:

您可以将变量设置为等于GameFlow.NormalGameFlow.NormalNoMove,然后将您拥有的值与它进行比较,如下所示:

GameFlow NormalOrNormalNoMove = GameFlow.Normal | GameFlow.NormalNoMove;
...
if ((Flow & NormalOrNormalNoMove) > 0)
{
    // Your code
}

【讨论】:

    【解决方案4】:

    也许有用

    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))
    

    【讨论】:

    • 添加类型检查:public static bool IsOneOf<T>(this T enumeration, params T[] enums) where T : Enum
    【解决方案5】:

    根据 C# 9,我会使用模式匹配编写类似的表达式。在这种情况下。

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

    【讨论】:

      【解决方案6】:
      var requiredFlows = new [] {
          GameFlow.NormalNoMove,
          GameFlow.Normal,
          // Other values of the GameFlow enum.
      }.ToHashSet();
      
      if (requiredFlows.Contains(currentFlow))
      {
          // Your code.
      }
      

      理想情况下,requiredFlows 应该是一个 private static readonly 字段。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-01-11
        • 2019-12-10
        • 1970-01-01
        • 2012-06-08
        • 2013-04-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多