使用 >= 和 <= 来指定枚举值是好的代码实践吗?

Is using >= and <= to specify enum values good code practice?

我正在与其他大约 8 个人一起处理一个项目,并且想知道这里的最佳代码实践,因为其他人将在未来几年内处理此代码。

假设我有一个包含 10 个值的枚举:

typedef enum {
    Tag1 = 1,
    Tag2,
    Tag3,
    Tag4,
    Tag5,
    Tag6,
    Tag7,
    Tag8,
    Tag9,
    Tag10
} Tag;

如果我想检查标签是否等于 Tag6、Tag7、Tag8、Tag9 或 Tag10,使用如下比较是好习惯:

if(myTag >= Tag6 && myTag <= Tag10) {
    //Do something
}

?

还是最好使用 OR 并检查每个标签?

使用 >= 和 <= 看起来更好,也不那么笨拙,但如果在线下,有人要在 Tag7 和 Tag8 之间插入一个新标签,它会搞乱所有逻辑。

我能期望有人不会在其他标签之间添加新标签吗?

Can I expect that someone wouldn't add a new Tag between other Tags?

我不会打赌。除非枚举的 ordinal/underlying 值具有某些固有的含义或顺序,否则我会避免过多地使用它们。

如果我真的希望有人能够插入额外的枚举而不调整所有检查,我只会使用范围检查。不过,这可能是一个相当罕见的案例。 Keith 使用 Priority 枚举给出了一个很好的例子,另一个我能想到的例子是日志级别。

确切的语法当然取决于语言,但我通常认为这样的语法最易读:

if(myTag in [Tag6, Tag7, Tag8]) {
    // ... 
} 

或者甚至更好地使用一些描述性变量名,这使得其他标签是什么一目了然:

topTags = [Tag6, Tag7, Tag8]

if(myTag in topTags) {
    // ... 
} 

是的,但是 用于表达 scale 值的枚举,例如:

enum Priority {
    None = 0,
    Low,
    Medium,
    High,
    Critical
}

那么这段代码是有意义的并且是可读的:

if(message.Priority >= Priority.Medium) {
     // Notify user
}

如果枚举不表示这样的比例,那么请避免使用 <>,因为它们可能相当混乱。请改用位标志。

标志枚举使用二进制值,以便可以组合值:

enum UserAudiences {
    // Basic values:  dec // binary
    None            = 0,  // 0000
    Client          = 1,  // 0001
    Employee        = 2,  // 0010
    Contractor      = 4,  // 0100
    Key             = 8,  // 1000

    // Combined:      dec // binary
    KeyClient       = 9,  // 1001 : Key + Client          
    BoardMember     = 10, // 1010 : Key + Employee        
    CounterParty    = 5,  // 0101 : Client + Contractor
    BusinessPartner = 13  // 1101 : Key + Client + Contractor
}

然后,在检查组合枚举值时,我们查看二进制数以及是否设置了适当的位。例如,如果我们想检查 UserAudiences.Employee,我们可以只查找代表 2 的位,如果它被设置,那么我们有一个包含它的枚举值:

if((message.Audience & UserAudiences.Employee) != 0) {
    // Post on intranet
} else {
    // Send externally
}

无法通过 KeyClientContractor 枚举的任意组合来设置该位,只有当 Employee 是其中之一时才能设置'source'枚举。

大多数语言都有这方面的帮助程序(或者您可以编写自己的帮助程序):

if(message.Audience.HasFlag(UserAudiences.Employee)) { ...

数学可以适用于任何基数 - 您可以使用十进制的 1、10、100 等。但是,您很快就会需要更大的数字。

最后,常规枚举使用单数名称,标记枚举使用复数名称,提示程序员是使用相等性检查还是按位检查。