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 真跑一下,打印第一个、第三个和最后一个:
| 5 | enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat }; | // 声明枚举 Days:Sun=0、Mon=1、tue=2……Sat=6 |
| 6 | | |
| 7 | static 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 就会报错。所以成员名最好统一首字母大写。
| 10 | Console.WriteLine((int)Days.Tue); | // 声明里是小写 tue,这里写成大写 Tue |
Program.cs(10,37): error CS0117: “Program.Days”未包含“Tue”的定义
4自己指定成员的值
成员可以用 = 指定值。没写值的成员,比前一个大 1,所以 Mid 是 2、Max 是 11(末尾没写分号也能编译):
| 5 | enum Level { Low = 1, Mid, High = 10, Max } | // Low=1、Mid=2;High=10、Max=11 |
查看完整代码(14 行)
| 1 | using System; | // 引入 System 命名空间 |
| 2 | | |
| 3 | class 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 行)
| 1 | using System; | // 引入 System 命名空间 |
| 2 | | |
| 3 | public 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
去掉前面的 ( 就编译不过:枚举和整数是两种类型,要转换得明着写出来。
| 9 | int x = Day.Sun; | // 不写 (int),直接把枚举交给 int 变量 |
Program.cs(9,17): error CS0266: 无法将类型“EnumTest.Day”隐式转换为“int”。存在一个显式转换(是否缺少强制转换?)
6枚举变量
枚举类型也能用来声明变量。直接打印出来的是名字,转成 int 才是数字:
| 9 | Day today = Day.Fri; | // 声明 Day 类型的变量 today,值是 Fri |
| 10 | Console.WriteLine(today); | // 直接打印:输出名字 Fri |
| 11 | Console.WriteLine((int)today); | // 转成 int 再打印:输出 5 |
| 12 | Day d = (Day)10; | // 把整数 10 强制转换成 Day,10 号没有成员 |
| 13 | Console.WriteLine(d); | // 没有名字可用,输出 10 |
( 照样能编译运行,可见枚举变量里装的就是一个整数,名字只是给它起的称呼。
7枚举是值类型
| 9 | Day a = Day.Mon; | // a 是 Mon |
| 10 | Day b = a; | // 把 a 的值复制一份给 b:b 是 Mon |
| 11 | a = Day.Sat; | // 只改 a:a 变成 Sat |
| 12 | Console.WriteLine(a); | // 输出 Sat |
| 13 | Console.WriteLine(b); | // b 是自己那份,还是 Mon |
b 拿到的是自己的一份值,之后 a 怎么改都和 b 无关。
8枚举不能继承
这有两层意思:枚举不能从别的类型派生,别的类型也不能从枚举派生。
| 6 | enum Weekend : Day { Sat, Sun }; | // 想让枚举 Weekend 从 Day 派生 |
| 7 | class 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 个字节:
| 5 | enum Day { Sun, Mon, Tue, Wed, Thu, Fri, Sat }; | // 没写底层类型,默认用 int |
| 6 | enum Color : byte { Red, Green, Blue }; | // : byte 指定成员用 byte 来存 |
| 7 | | |
| 8 | static void Main() | // 程序入口 Main 方法 |
| 9 | { | // Main 开始 |
| 10 | Console.WriteLine(sizeof(Day)); | // sizeof 取类型占几个字节:输出 4 |
| 11 | Console.WriteLine(sizeof(Color)); | // 输出 1 |
9小结
- 枚举是一排有名字的整数常量,用
enum声明。 - 默认从 0 开始依次加 1;也可以自己指定,没写值的比前一个大 1。
- 要数字就强制转换成
int;直接打印得到名字。 - 枚举是值类型,不能继承;冒号后面写的是底层类型。
下一节:想把数据和操作数据的方法装进一个能造出很多对象的模板,该怎么写?
