Enum 应该以0开头还是以1开头?

假设我已经定义了以下 Enum:

public enum Status : byte
{
Inactive = 1,
Active = 2,
}

使用 enum 的最佳实践是什么?它应该像上面的例子那样以 1开始,还是像下面这样以 0(没有显式值)开始:

public enum Status : byte
{
Inactive,
Active
}
94373 次浏览

我想说的是,最佳实践是不给它们编号,并让它是隐式的——这将从0开始。由于它的隐含的语言偏好,总是好的遵循:)

我将以0开始一个布尔型枚举。

除非“主动”意味着“非主动”:)

这保留了那些的标准。

不要分配任何数字。 就像它应该被使用的那样使用它。

除非您有特定的理由更改枚举,否则将枚举保留为默认值,默认值从零开始。

public enum Status : byte
{
Inactive,
Active
}

我喜欢以0开始我的枚举,因为这是默认值,但是我也喜欢包含一个 Unknown 值,值为 -1。这就成为默认值,有时可以帮助进行调试。

框架设计指南 :

Something DO 对简单枚举提供一个值为零。

可以考虑将该值称为“无”如果这样一个值不适合这个特定的枚举,那么枚举最常见的默认值应该被赋予基础值0。

框架设计指南/标志枚举设计 :

Something 避免使用标志枚举值为零,除非该值表示“所有标志都被清除”,并且按照下一条指导原则指定了适当的名称。

Something DO 命名标志枚举的零值。对于标志枚举,该值必须始终表示“清除所有标志”

Enum 是一种值类型,如果没有显式初始化,它的默认值(例如类中的 Enum 字段)将为0。

因此,您通常希望将0作为已定义的常量(例如,Unknown)。

在您的示例中,如果希望 Inactive为默认值,那么它应该为零。否则,您可能需要考虑添加一个常量 Unknown

有些人建议不要为常量显式指定值。在大多数情况下,这可能是个不错的建议,但在某些情况下,你会想这样做:

  • 标记枚举

  • 其值用于与外部系统互操作的枚举(例如 COM)。

除非您有充分的理由使用原始值,否则应该只使用隐式值并使用 Status.ActiveStatus.Inactive引用它们。

问题是,您可能希望将数据存储在平面文件或数据库中,或者使用其他人创建的平面文件或数据库。如果是您自己编写的,那么编号就要符合 Enum 的用途。

如果数据不是你的,你当然会想使用原来开发人员用作编号的东西。

如果您计划将 Enum 作为一组标志使用,那么有一个值得遵循的简单约定:

enum Example
{
None      = 0,            //  0
Alpha     = 1 << 0,       //  1
Beta      = 1 << 1,       //  2
Gamma     = 1 << 2,       //  4
Delta     = 1 << 3,       //  8
Epsilon   = 1 << 4,       // 16
All       = ~0,           // -1
AlphaBeta = Alpha | Beta, //  3
}

值应该是2的幂,并且可以使用位移操作来表示。None,显然应该是 0,但 All是不太明显的 -1~00的二进制负值,并且产生一个将每个位设置为 1它表示一个值 -1的数字。对于复合标志(通常用于方便) ,其他值可以使用按位或操作符 |合并。

好吧,我想我不同意大多数回答说不要明确地给它们编号。我总是显式地给它们编号,但这是因为在大多数情况下,我最终将它们保存在一个数据流中,并将它们存储为一个整数值。如果不显式地添加这些值,然后再添加一个新值,则可能会中断序列化,从而无法准确地加载旧的持久化对象。如果要对这些值进行任何类型的持久化存储,那么我强烈建议显式设置这些值。

首先,除非您为某个原因指定特定的值(数值在其他地方有意义,即。数据库或外部服务)则根本不指定数值,而是让它们显式化。

其次,应该始终有一个零值项(在非标志枚举中)。该元素将用作默认值。

我会说,这取决于你如何使用它们。对于标记 enum,最好使 None值为0,如下所示:

[Flags]
enum MyEnum
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
All = Option1 | Option2 | Option3,
}

当枚举可能被映射到数据库查找表时,我会从1开始。对于专业编写的代码来说,这并不重要,但是这可以提高可读性。

在其他情况下,我会让它保持原样,不管它们是从0开始还是从1开始。

如果你从1开始,那么你可以很容易地得到你的东西计数。

{
BOX_THING1     = 1,
BOX_THING2     = 2,
BOX_NUM_THING  = BOX_THING2
};

如果从0开始,那么使用第一个值作为未初始化的值。

{
BOX_NO_THING   = 0,
BOX_THING1     = 1,
BOX_THING2     = 2,
BOX_NUM_THING  = BOX_THING2
};

除非有必要,否则不要从0开始,比如将它们用作数组或列表的索引,或者如果有其他实际原因(比如在按位操作中使用它们) ,否则不要从0开始。

你的 enum应该从它需要的地方开始。它也不需要是连续的。如果值是显式设置的,则需要反映一些语义意义或实际考虑。例如,“墙上的瓶子”的 enum应该从1到99编号,而4的功率的 enum应该从4开始,继续编号为16,64,256,等等。

此外,只有在 enum表示有效状态时,才应该向它添加一个零值元素。有时“无”、“未知”、“丢失”等是有效值,但很多时候它们不是。

如果未指定编号,则从0开始。

显式很重要,因为枚举通常被序列化并存储为 int 而不是字符串。

对于存储在数据库中的任何枚举,我们总是显式地为选项编号,以防止在维护期间发生移位和重新分配。

根据 Microsoft,推荐的约定是使用第一个零选项来表示未初始化的或最常见的默认值。

下面是从1而不是0开始编号的快捷方式。

public enum Status : byte
{
Inactive = 1,
Active
}

如果您希望设置标志值以便对枚举值使用位运算符,请不要从零开始编号。

如果枚举以0开头,那么就不需要赋整数值。它以0开头,增量为1。非活动 = 0,活动 = 1。

 public enum Status : byte{
Inactive,
Active
}

如果你想为第一个指定值,你需要为它指定值。这里,Inactive = 1,Active = 0。

 public enum Status : byte{
Inactive =1,
Active =0
}

如果 Enum 没有默认值的概念,则首选将第一个 Enum 成员的值设置为 1,原因如下。

直觉

C # 默认将 Enum 设置为 0。因此,除非第一个 Enum 成员实际上是默认值,否则直觉上不会将其映射到 0

允许强制执行 Web API 所需的枚举

考虑以下最小 Web API:

using Microsoft.AspNetCore.Mvc;
using MiniValidation; // See https://github.com/dotnet/aspnetcore/issues/39063
using System.ComponentModel.DataAnnotations;


var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();


// Returns true if validation is successful, false otherwise
app.MapGet("/", ([FromBody] MyClass myClass) => MiniValidator.TryValidate(myClass, out _));


app.Run();


class MyClass
{
[EnumDataType(typeof(MyEnum))] // Validates `MyEnum` is a valid enum value
public MyEnum MyEnum { get; set; }
}


enum MyEnum { One, Two }

假设客户机必须为 MyEnum提供一个值; 发送一个空 JSON 字符串 {}会导致端点返回 false

但是,上面的实现返回 true; 模型验证通过,因为 C # 默认 MyEnum00映射到 MyEnum.One

通过将 Enum 修改为 enum MyEnum { One = 1, Two },端点返回 false; 模型验证失败,因为 Enum 的任何成员都没有映射到 0


注意

Enum 的指南文档 状态

DO 在简单枚举上提供一个零值。

但是,违反这一指导方针似乎并不会导致负面后果。