枚举类型(或枚举类型)是由基础整型数值类型的一组命名常量定义的值类型。 若要定义枚举类型,请使用 enum 关键字并指定 枚举成员的名称:
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
默认情况下,枚举成员的关联常量值属于类型 int;它们以零开头,并按定义文本顺序增加一个。 可以将任何其他 整型数值 类型显式指定为枚举类型的基础类型。 还可以显式指定关联的常量值,如以下示例所示:
enum ErrorCode : ushort
{
None = 0,
Unknown = 1,
ConnectionLost = 100,
OutlierReading = 200
}
不能在枚举类型的定义中定义方法。 若要将功能添加到枚举类型,请创建 扩展方法。
枚举类型的 E 默认值是表达式 (E)0生成的值,即使零没有相应的枚举成员也是如此。
从零开始的隐式转换
C# 允许从文本值 0 到任何枚举类型以及从 const 等于零的值进行隐式转换。 当枚举不包含值为零的成员时,此行为可能会导致意外结果:
public enum GpioPort
{
GpioA = 1,
GpioB,
GpioC,
GpioD
}
public class ZeroConversionExample
{
public static void Main()
{
// This compiles without warning but creates an invalid enum value
GpioPort port1 = (GpioPort)0;
Console.WriteLine($"port1: {port1}"); // Output: port1: 0
// This also compiles due to implicit conversion from zero
GpioPort port2 = GetPort(0);
Console.WriteLine($"port2: {port2}"); // Output: port2: 0
// Check if the enum value is valid
bool isValid1 = Enum.IsDefined(typeof(GpioPort), port1);
bool isValid2 = Enum.IsDefined(typeof(GpioPort), port2);
Console.WriteLine($"port1 is valid: {isValid1}"); // Output: port1 is valid: False
Console.WriteLine($"port2 is valid: {isValid2}"); // Output: port2 is valid: False
// Safer approach - validate enum values
if (Enum.IsDefined(typeof(GpioPort), 0))
{
GpioPort safePort = (GpioPort)0;
}
else
{
Console.WriteLine("Value 0 is not a valid GpioPort");
// Handle the invalid case appropriately
}
}
public static GpioPort GetPort(GpioPort port)
{
return port;
}
}
在前面的示例中,两者都 port1 分配了 port2 值 0,但没有 GpioPort 具有该值的成员。 该方法 Enum.IsDefined 确认这些枚举值无效。
存在此隐式转换,因为 0 位模式是所有结构类型的默认值,包括所有枚举类型。 但是,它可以在代码中引入 bug。 为避免这些问题:
- 你几乎应该始终在枚举中定义具有值
0的成员。 - 用于 Enum.IsDefined 在从数值类型转换时验证枚举值。
- 使用可能隐式转换为枚举类型的数值参数时,请谨慎。
可以使用枚举类型来表示一组互斥值或选项组合中的选项。 若要表示选项的组合,请将枚举类型定义为位标志。
作为位标志的枚举类型
如果希望枚举类型表示选项的组合,请为这些选项定义枚举成员,以便单个选择是位字段。 也就是说,这些枚举成员的关联值应该是 2 的幂。 然后,可以使用 按位逻辑运算符 | 或 & 分别组合选项或相交选项组合。 若要指示枚举类型声明位字段,请向其应用 Flags 属性。 如以下示例所示,还可以在枚举类型的定义中包含一些典型组合。
[Flags]
public enum Days
{
None = 0b_0000_0000, // 0
Monday = 0b_0000_0001, // 1
Tuesday = 0b_0000_0010, // 2
Wednesday = 0b_0000_0100, // 4
Thursday = 0b_0000_1000, // 8
Friday = 0b_0001_0000, // 16
Saturday = 0b_0010_0000, // 32
Sunday = 0b_0100_0000, // 64
Weekend = Saturday | Sunday
}
public class FlagsEnumExample
{
public static void Main()
{
Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;
Console.WriteLine(meetingDays);
// Output:
// Monday, Wednesday, Friday
Days workingFromHomeDays = Days.Thursday | Days.Friday;
Console.WriteLine($"Join a meeting by phone on {meetingDays & workingFromHomeDays}");
// Output:
// Join a meeting by phone on Friday
bool isMeetingOnTuesday = (meetingDays & Days.Tuesday) == Days.Tuesday;
Console.WriteLine($"Is there a meeting on Tuesday: {isMeetingOnTuesday}");
// Output:
// Is there a meeting on Tuesday: False
var a = (Days)37;
Console.WriteLine(a);
// Output:
// Monday, Wednesday, Saturday
}
}
有关详细信息和示例,请参阅 System.FlagsAttribute API 参考页和 非独占成员以及 API 参考页的 System.Enum Flags 属性部分。
System.Enum 类型和枚举约束
该 System.Enum 类型是所有枚举类型的抽象基类。 它提供了许多方法来获取有关枚举类型及其值的信息。 有关详细信息和示例,请参阅 System.Enum API 参考页。
可以在 System.Enum 基类约束(称为 枚举约束)中使用,以指定类型参数是枚举类型。 任何枚举类型也满足 struct 约束,该约束用于指定类型参数是不可为 null 的值类型。
转换
对于任何枚举类型,枚举类型与其基础整型之间存在显式转换。 如果将枚举值 转换为 其基础类型,则结果是枚举成员对应的整数值。
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
public class EnumConversionExample
{
public static void Main()
{
Season a = Season.Autumn;
Console.WriteLine($"Integral value of {a} is {(int)a}"); // output: Integral value of Autumn is 2
var b = (Season)1;
Console.WriteLine(b); // output: Summer
var c = (Season)4;
Console.WriteLine(c); // output: 4
}
}
Enum.IsDefined使用该方法确定枚举类型是否包含具有特定关联值的枚举成员。
对于任何枚举类型,都存在分别与 类型的System.Enum相互转换。
C# 语言规范
有关更多信息,请参阅 C# 语言规范的以下部分: