通过


C# 枚举

小窍门

开发软件的新手? 首先开始 学习入门 教程。 一旦你需要在代码中表示一组固定选项时,你将遇到枚举。

是否在其他语言中有经验? C# 枚举的工作方式与 Java 或 C++ 中的枚举类似,还支持位标志和模式匹配。 浏览 标志switch 表达式 部分,以查找特定于 C# 的模式。

枚举类型(或枚举)定义一组由整数值支持的命名常量。 当值必须是固定选项集之一(星期几、HTTP 状态代码、日志级别或方向)时,请使用枚举。 枚举使代码比原始整数常量更具可读性和不易出错,因为编译器会确保使用命名值。

声明枚举

使用 enum 关键字后接类型名称及其成员,定义枚举:

enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

默认情况下,基础类型为 int,值以一个开头 0 并递增。 Season.Spring0Season.Summer1,等等。

指定基础类型和显式值

可以选择不同的整型类型并分配显式值来控制数字表示形式:

enum HttpStatus : ushort
{
    OK = 200,
    NotFound = 404,
    InternalServerError = 500
}

当数字具有外部含义(如 HTTP 状态代码或协议标识符)时,请使用显式值。 基础类型可以是任何整型类型,但char除外。 使用byteshortushortintuintlongulong

在 switch 表达式中使用枚举

枚举可以自然地与 switch 表达式和模式匹配配合使用。 如果未处理所有成员,编译器会发出警告,这有助于防止在以后添加新值时出现 bug:

static string DescribeSeason(Season season) => season switch
{
    Season.Spring => "Flowers bloom and temperatures rise.",
    Season.Summer => "Long days and warm weather.",
    Season.Autumn => "Leaves change color and fall.",
    Season.Winter => "Short days and cold temperatures.",
    _ => throw new ArgumentOutOfRangeException(nameof(season))
};
var today = Season.Autumn;
Console.WriteLine(DescribeSeason(today));

丢弃模式 (_) 处理未显式列出的任何值。 模式匹配 是一项 C# 功能,用于针对形状或条件测试值。 在此示例中,每个 case 用于检查枚举是否与特定成员匹配。 Switch 表达式是多种模式匹配形式之一。 有关模式匹配的详细信息,请参阅 模式匹配

位标志

当枚举表示的是选项的组合而非单个选项时,请将每个成员定义为2的幂并应用FlagsAttribute

[Flags]
enum FileAccess
{
    None = 0,
    Read = 1,
    Write = 2,
    Execute = 4,
    ReadWrite = Read | Write,
    All = Read | Write | Execute
}

通过使用 | 运算符合并值,并使用 HasFlag 测试各个标志:

var permissions = FileAccess.Read | FileAccess.Write;

Console.WriteLine(permissions);                          // ReadWrite
Console.WriteLine(permissions.HasFlag(FileAccess.Read)); // True
Console.WriteLine(permissions.HasFlag(FileAccess.Execute)); // False

[Flags] 属性还会影响 ToString()。 它以逗号分隔的名称(如 Read, Write)而不是原始数字的形式显示组合值。 有关详细信息,请参阅 System.FlagsAttribute

在枚举和整数之间进行转换

显式转换用于在枚举和它的底层整数类型之间进行转换。

var status = HttpStatus.NotFound;
ushort code = (ushort)status;
Console.WriteLine($"Status: {status} ({code})"); // Status: NotFound (404)

var fromCode = (HttpStatus)200;
Console.WriteLine(fromCode); // OK

请注意,将整数转换为枚举不会验证该值是否与某个已定义的成员匹配。 使用 Enum.IsDefined 来检查从外部源接受的数字输入的有效性。

分析字符串并遍历值

Enum 类提供用于分析字符串和循环访问所有已定义值的方法:

// Parse a string to an enum value:
var parsed = Enum.Parse<Season>("Winter");
Console.WriteLine(parsed); // Winter

// Try to parse safely. It returns false only when the input can't be parsed. Call Enum.IsDefined to validate named members:
if (Enum.TryParse<Season>("Monsoon", out var unknown))
{
    Console.WriteLine(unknown);
}
else
{
    Console.WriteLine("'Monsoon' is not a valid Season"); // 'Monsoon' is not a valid Season
}

// Iterate over all values in an enum:
foreach (var season in Enum.GetValues<Season>())
{
    Console.WriteLine($"{season} = {(int)season}");
}
// Spring = 0
// Summer = 1
// Autumn = 2
// Winter = 3

使用 Enum.TryParse<TEnum>(String, Boolean, TEnum) 代替 Enum.Parse<TEnum>(String) 当输入可能无效时。 它返回 false 而不是引发异常。

另见