有没有一种好的方法可以在C#中的System.Enum上使用逻辑运算

本文关键字:System 中的 Enum 逻辑运算 一种 方法 有没有 | 更新日期: 2023-09-27 18:22:24

我正在通过编写一个小游戏来学习C#。作为其中的一部分,我将设备的输入映射到一个枚举中,该枚举包含游戏中的动作,这些动作是从按钮和动作对的字典中定义的。

例如,我有一个类似的东西,示意性地:

[Flags]
enum Actions { None=0, MoveUp=1, MoveDown=2, MoveLeft=4, MoveRight=8 }
Actions currentActions;
private void SetActions()
{
 currentActions = Actions.None; 
 if (UpPressed)
     currentAction |= Actions.MoveUp;
 (etc)
}
public void Update()
{
 SetActions();
 if (currentActions & Actions.MoveUp) == Actions.MoveUp)
     MoveUp();
 (etc)
}

我根据输入设置动作,然后根据列表中的动作更新游戏状态。

我想做的是,有一个新的类"ActionManager",它包含与操作相关的数据和方法;

public Enum currentActions;
public void SetActions();
public void UpdateActions();

以及其他类,例如,与菜单相对应的类,可以将它们自己的枚举添加到该全局枚举中,从而在负责处理输入的每个类内部定义每一组可能的动作,而不是在全局枚举中预定义。

但我不能这样做,因为我不能向枚举添加或从中删除,也不能从System.enum继承。我能想到的唯一方法是枚举列表:

// In class ActionManager
public List<Enum> allowedActions = new List<Enum>();
public List<Enum> currentActions = new List<Enum>();
public void SetActions(Enum action)
{
 currentActions.Clear();
 foreach (Enum e in allowedActions)
     if (IsKeyPressed(e))             
         currentActions.Add(e);
}
// In, say, GameMenu class
[Flags]
enum MenuActions { None=0, MenuUp = 1, ... }
private actionManager ActionManager = new ActionManager();
public void DefineActions()
{
 foreach (MenuActions m in Enum.GetValues(typeof(MenuActions)))
     actionManager.allowedActions.Add(m);
     //also define the key corresponding to the action 
     //here, from e.g., a config file
     //and put this into a Dictionary<buttons, actions>
}
public Update()
{
 actionManager.Update();
 if (actionManager.currentActions.Contains(MenuActions.MenuUp))
 (etc)
}

但这似乎很愚蠢,我用枚举列表取代了廉价的逻辑运算,这似乎很尴尬。它还迫使我使用.Contains等,而不是算术,并在值类型更有意义的地方使用引用类型(而且泛型列表无论如何都不应该对外公开)。

我意识到我也可以用int替换List,并将其他类的所有枚举强制转换为int,这样我就可以一起执行操作,但这没有枚举的类型安全性。

因此,我的问题是:有没有一种方法可以用枚举实现这一点?有没有一种更聪明的方法来做这类事情(要么用枚举,要么完全用另一种方法)?

我这样做是为了学习语言,所以如果有更好的方法来做这样的事情,我将不胜感激!

有没有一种好的方法可以在C#中的System.Enum上使用逻辑运算

是;您可以使用位运算符:

Actions allowedActions = Actions.Up | Actions.Right;
allowedActions |= Actions.Down; // to show building at runtime
Actions currentActions = Actions.Right | Actions.Down; // union

然后使用各种&/|/~进行测试和更改:

var limitedToAllowed = currentActions & allowedActions; // intersect
// disallow "up" for some reason
allowedActions &= ~Actions.Up;

您可以通过以下方式测试重叠:

// test if **any** of the currentActions is in the allowedActions
bool anyAllowed = currentActions & allowedActions != 0;
// test if **all** of the currentActions are in the allowedActions
bool allAllowed = currentActions & allowedActions == currentActions;

关于"允许哪些值"的注释通常可以通过添加.All枚举(在您的情况下为15)或在运行时完成:

Actions actions = 0;
foreach(Actions action in Enum.GetValues(typeof(Actions))) {
    actions |= action;
}
// actions now has all the flags that are defined
相关文章: