首页 > 解决方案 > 如何在 C# 中修饰枚举

问题描述

(抱歉,如果此类问题应该转而进行代码审查。)

我想知道用附加信息扩充枚举的最佳方法。具体情况是,我正在开发一个游戏,其中我有一个表示一种类型的 Infliction 的枚举,它可能是物理的、魔法的或与状态相关的。

例如:

enum InflictionTypes { Pierce, Slash, Bruise, Heat, Shock, Cold, Metal, Salt, Wet}

在某些地方,我的战斗系统对这些都是一样的(例如,各种盔甲或保护装置如何工作)。但是在其他地方,战斗系统需要对它们进行不同的处理(例如,如果它们穿过盔甲,它们的实际效果。)所以我需要某种方式来区分种类,并且遇到了枚举的限制。

如果可以创建枚举的层次结构,我可以这样做——拥有一个 InflictionTypes 的“基本枚举”并从中“派生”以拥有单独的种类。但显然这很疯狂。

或者,如果可以用其他一些信息来修饰枚举,那会起作用,但枚举显然不包含字段。

我正在考虑几种可能性:

可能性A:创建一个装饰器类

我可以创建一个将枚举作为字段保存并将其他信息(可能是另一个枚举:InflictionOutcome)保存为字段、属性或方法的类。我将使用静态构造函数来初始化用于提供信息的私有字典。

这个选项的一个轻微的负面影响是,通常可能很难找到一个好的名称来捕捉这个类的含义,它本质上与它所装饰的枚举具有相同的目的。(在这种情况下,“Infliction”并不是特别好,因为它代表了这个 InflictionType 与其他一些信息的组合。)

可能性 B:创建枚举扩展方法

另一种选择是为枚举编写扩展函数以提供附加信息。从代码上看,这似乎很不优雅,因为扩展方法要么沿着 switch 语句,要么需要在方法内生成查找字典。

可能性 C:不要使用枚举

不言自明。考虑到这些信息在代码的其他部分是如何使用的,如果不能有一个枚举,那将是非常不幸的。

我想知道是否有更好的选择;似乎应该有。

标签: c#enums

解决方案


怎么用[Flags]?就像是:

[Flags]
public enum InflictionTypes
{
    ArmourProtects = 0x0001_0000,
    Environmental = 0x0002_0000,
    Pierce = 0x0001 | ArmourProtects,
    Slash = 0x0002 | ArmourProtects,
    Bruise = 0x0004,
    Heat = 0x0008 | Environmental,
    Shock = 0x0010,
    Cold = 0x0020 | Environmental,
    Metal = 0x0040,
    Salt = 0x0080,
    Wet = 0x0100,
}

然后创建用于测试事物的扩展方法:

public static bool IsEnvironmental(this InflictionTypes anEnumValue)
{
    return (anEnumValue & InflictionTypes.Environmental) != 0;
}

缺点是您最终将值和类别混合在同一类型中。

更新

价值观和类别的混合让我感到困扰。但是,这有效(使用您想要设置位模式的任何策略):

[Flags]
public enum InflictionGroups
{
    ArmourProtects = 0x0001_0000,
    Environmental = 0x0002_0000,
}

[Flags]
public enum InflictionTypes
{
    Pierce = 0x0001 | InflictionGroups.ArmourProtects,
    Slash = 0x0002 | InflictionGroups.ArmourProtects,
    Bruise = 0x0004,
    Heat = 0x0008 | InflictionGroups.Environmental,
    Shock = 0x0010,
    Cold = 0x0020 | InflictionGroups.Environmental,
    Metal = 0x0040,
    Salt = 0x0080,
    Wet = 0x0100,
}

一个缺点是您不能在两种不同的枚举类型之间使用|和。&但是,您可以在扩展方法中执行此操作:

public static bool IsEnvironmental(this InflictionTypes anEnumValue)
{
    return ((int)anEnumValue & (int)InflictionGroups.Environmental) != 0;
}

推荐阅读