第 19 节 · 第二部分 流程、方法与数据

枚举(Enum)

枚举是一排有名字的整数常量,变量里存的是整数,名字只是称呼。

时长 5:31授课计划第 7 周

学完这一节,你能

讲义

跟着视频的顺序写。每行代码都有注释,代码和运行结果都是实际运行得到的。

1枚举是什么

一周七天用 0、1、2 来表示,很容易搞混。枚举(关键字 enum)让你用 Sun、Mon 这样的名字代替这些数字:它是一组有名字的整数常量,而且是值类型,这一点讲完例子再验证。

视频里把它比成一排铭牌:每块铭牌是一个成员,正面刻名字,下面的钢印刻它代表的整数;滑轨上的滑块是枚举变量,停在哪块前面,值就是哪个。真实内存里没有铭牌,变量里存的只是那个整数。

2声明枚举

写法是:先写 enum,再写枚举名,然后在一对花括号里列出成员名,中间用逗号隔开,例如 enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };。

这里声明的是一个枚举类型(教程小标题写成“声明 enum 变量”),变量要等后面才出现。花括号后面的分号可写可不写,下面的 Level 就没写,照样能编译。

3成员的值:默认从 0 开始

默认第一个成员是 0,后面每一个比前一个大 1。用教程的 Days 真跑一下,打印第一个、第三个和最后一个:

C# · 第 5-11 行
5enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat };// 声明枚举 Days:Sun=0、Mon=1、tue=2……Sat=6
6
7static void Main()// 程序入口 Main 方法
8{// Main 开始
9 Console.WriteLine((int)Days.Sun);// (int) 把枚举转成整数:输出 0
10 Console.WriteLine((int)Days.tue);// 第三个成员:输出 2
11 Console.WriteLine((int)Days.Sat);// 最后一个成员:输出 6

教程第三个成员写的是小写的 tue,能编译;但 C# 区分大小写,用的时候写成大写的 Tue 就会报错。所以成员名最好统一首字母大写。

C# · 第 10 行
10Console.WriteLine((int)Days.Tue);// 声明里是小写 tue,这里写成大写 Tue
编译报错
Program.cs(10,37): error CS0117: “Program.Days”未包含“Tue”的定义

4自己指定成员的值

成员可以用 = 指定值。没写值的成员,比前一个大 1,所以 Mid 是 2、Max 是 11(末尾没写分号也能编译):

C# · 第 5 行
5enum Level { Low = 1, Mid, High = 10, Max }// Low=1、Mid=2;High=10、Max=11
查看完整代码(14 行)
C#
1using System;// 引入 System 命名空间
2
3class Program// 定义 Program 类
4{// Program 类开始
5 enum Level { Low = 1, Mid, High = 10, Max }// 枚举 Level:1、2、10、11
6
7 static void Main()// 程序入口 Main 方法
8 {// Main 开始
9 Console.WriteLine((int)Level.Low);// 输出 1
10 Console.WriteLine((int)Level.Mid);// 前一个是 1,输出 2
11 Console.WriteLine((int)Level.High);// 指定了 10,输出 10
12 Console.WriteLine((int)Level.Max);// 前一个是 10,输出 11
13 }// Main 结束
14}// Program 类结束

5教程实例:转成 int

查看完整代码(14 行)
C#
1using System;// 引入 System 命名空间
2
3public class EnumTest// 定义 EnumTest 类
4{// EnumTest 类开始
5 enum Day { Sun, Mon, Tue, Wed, Thu, Fri, Sat };// 在类里面声明枚举 Day:Sun=0……Fri=5、Sat=6
6
7 static void Main()// 程序入口 Main 方法
8 {// Main 开始
9 int x = (int)Day.Sun;// 把 Day.Sun 强制转换成 int:x = 0
10 int y = (int)Day.Fri;// 把 Day.Fri 强制转换成 int:y = 5
11 Console.WriteLine("Sun = {0}", x);// 输出 Sun = 0
12 Console.WriteLine("Fri = {0}", y);// 输出 Fri = 5
13 }// Main 结束
14}// EnumTest 类结束
运行结果
Sun = 0
Fri = 5

去掉前面的 (int) 就编译不过:枚举和整数是两种类型,要转换得明着写出来。

C# · 第 9 行
9int x = Day.Sun;// 不写 (int),直接把枚举交给 int 变量
编译报错
Program.cs(9,17): error CS0266: 无法将类型“EnumTest.Day”隐式转换为“int”。存在一个显式转换(是否缺少强制转换?)

6枚举变量

枚举类型也能用来声明变量。直接打印出来的是名字,转成 int 才是数字:

C# · 第 9-13 行
9Day today = Day.Fri;// 声明 Day 类型的变量 today,值是 Fri
10Console.WriteLine(today);// 直接打印:输出名字 Fri
11Console.WriteLine((int)today);// 转成 int 再打印:输出 5
12Day d = (Day)10;// 把整数 10 强制转换成 Day,10 号没有成员
13Console.WriteLine(d);// 没有名字可用,输出 10

(Day)10 照样能编译运行,可见枚举变量里装的就是一个整数,名字只是给它起的称呼。

7枚举是值类型

C# · 第 9-13 行
9Day a = Day.Mon;// a 是 Mon
10Day b = a;// 把 a 的值复制一份给 b:b 是 Mon
11a = Day.Sat;// 只改 a:a 变成 Sat
12Console.WriteLine(a);// 输出 Sat
13Console.WriteLine(b);// b 是自己那份,还是 Mon

b 拿到的是自己的一份值,之后 a 怎么改都和 b 无关。

8枚举不能继承

这有两层意思:枚举不能从别的类型派生,别的类型也不能从枚举派生。

C# · 第 6-7 行
6enum Weekend : Day { Sat, Sun };// 想让枚举 Weekend 从 Day 派生
7class Holiday : Day { }// 想让类 Holiday 从 Day 派生
编译报错
Program.cs(7,21): error CS0509: “EnumTest.Holiday”: 无法从密封类型“EnumTest.Day”派生
Program.cs(6,20): error CS1008: 应输入类型 byte、sbyte、short、ushort、int、uint、long 或 ulong

枚举冒号后面只能写整数类型,这不是继承,而是指定成员用哪种整数来存(叫底层类型)。默认是 int,占 4 个字节;写成 byte 只占 1 个字节:

C# · 第 5-11 行
5enum Day { Sun, Mon, Tue, Wed, Thu, Fri, Sat };// 没写底层类型,默认用 int
6enum Color : byte { Red, Green, Blue };// : byte 指定成员用 byte 来存
7
8static void Main()// 程序入口 Main 方法
9{// Main 开始
10 Console.WriteLine(sizeof(Day));// sizeof 取类型占几个字节:输出 4
11 Console.WriteLine(sizeof(Color));// 输出 1

9小结

  • 枚举是一排有名字的整数常量,用 enum 声明。
  • 默认从 0 开始依次加 1;也可以自己指定,没写值的比前一个大 1。
  • 要数字就强制转换成 int;直接打印得到名字。
  • 枚举是值类型,不能继承;冒号后面写的是底层类型。

下一节:想把数据和操作数据的方法装进一个能造出很多对象的模板,该怎么写?

检查题

5 道,选完马上告诉你对不对。

  1. 1enum Level { Low = 1, Mid, High = 10, Max } 里 Max 的值是?

  2. 2Day today = Day.Fri; Console.WriteLine(today); 输出?

  3. 3int x = Day.Sun; 会怎样?

  4. 4enum Days { Sun, Mon, tue } 之后写 Days.Tue?

  5. 5Day a = Day.Mon; Day b = a; a = Day.Sat; 之后 b 是?