向编译器声明一个枚举。
[attributes] [Modifiers]
ENUM <idEnumName> [AS type]
memberName [:= value]
[...]
END [ENUM]
Attributes | 一个可选的特性列表,用于描述实体的元信息,例如在 MsTest 类库中包含测试的方法/函数上的 [TestMethod] 属性。请注意,当特性写在关键字上方的行时,特性必须在同一行或以分号结尾。 |
Modifiers | 一个可选的修饰符列表,用于指定实体的可见性或范围,例如:PUBLIC, PROTECTED, HIDDEN, INTERNAL, SEALED, ABSTRACT 或 STATIC. |
idEnum | 枚举的有效标识符名称。 枚举名在名称空间内必须是唯一的。 |
AS type | 枚举成员的数据类型(可选)。 |
memberName | 枚举成员的名称。 |
使用 ENUM 关键字声明的类型是“枚举”类型,它由一组命名常量组成,称为枚举列表。枚举类型隐式继承自 System.Enum。
枚举类型具有基础类型,即枚举列表中项的类型。默认的基础类型是 INT;如果指定了 AS 子句,则类型可以是任何有符号或无符号整数类型,但不能是 System.Char。
默认情况下,枚举列表中的第一个成员的值为 0。每个其他成员的值是前一个成员的值加 1。元素的值可以通过使用赋值运算符(:=)后跟文字整数值或在编译时解析为整数值的表达式来显式设置为基础类型范围内的任何值。两个或更多成员可以显式设置为相同的值。
ENUM E 的默认值是表达式 (E)0.,这取决于是否存在具有值 0 的成员,可能代表枚举类型的成员。
通过指定枚举类型的名称和成员的名称,用句点分隔,来引用枚举成员。如果枚举类型是在当前编译的命名空间中声明的,则枚举类型的名称就足够了。否则,必须使用完全限定的枚举名称(例如 System.Windows.Forms.MessageBoxButtons),或者使用 USING 指令导入命名空间。
可以在 ENUM 上放置 System.FlagsAttribute 属性,以指示可以使用按位 OR 运算符组合枚举的元素。
枚举名称可以包括一个或多个命名空间名称,用句点分隔。如果在枚举名称中找不到句点,则假定默认命名空间。默认命名空间是输出程序集名称的基本名称,除非通过 /ns 编译器选项明确覆盖。
ENUM days
Sunday // 0
Monday // 1
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
END CLASS
FUNCTION example1() AS VOID
LOCAL i AS INT
i := (INT) days.Friday
? days.Friday, i // prints: Friday 5
ENUM direction
north // 具有默认值 0
east := 90
south := 180
west := 270
END ENUM
FUNCTION example2( x AS direction ) AS VOID
IF x == direction.north
goNorth()
ELSEIF x == direction.east
goEast()
ELSEIF x == direction.south
goSouth()
ELSEIF x == direction.west
goWest()
ELSE
Debug.Assert( "direction 的值未知" )
ENDIF
[System.FlagsAttribute];
ENUM CarOptions
SunRoof := 0x1
Spoiler := 0x2
FogLights := 0x4
TintedWindows := 0x8
END ENUM
FUNCTION example3() AS VOID
LOCAL options AS CarOptions
options := CarOptions.SunRoof | CarOptions.FogLights
? options // prints: SunRoof, FogLights
? (INT) options // prints: 5
在第一个和第三个示例中,请注意在枚举类型上使用 ? 语句会打印出枚举的文本值。这是因为枚举成员的名称存储在程序集的元数据中,而 System.Enum 中的 ToString() 方法(每个枚举类型都继承自它)使用元数据来获取并返回枚举成员的名称,而不是其基础数值。
还要注意,即使从 Enum.ToString() 返回枚举成员的文本名称,编译器在编译代码时使用的是字面数值。因此,例如 IF x == direction.north 实际上编译为 IF x == 0,因为枚举成员和它们的基础值之间的映射发生在编译时而不是运行时。这使得使用枚举类型与 #define 一样高效,同时提供更高级别的类型安全性和编译时错误检查。然而,这也意味着更改枚举成员的值可能会导致使用该枚举的现有代码出现问题,除非重新编译。