第14章 枚举
在介绍枚举的概念之前,先从枚举的优点谈起,并适当举例说明,让大家先有一个感性认识,更易于理解。使用枚举的好处主要有如下几个方面:
❑枚举使代码更清晰,因为它允许用描述性的名称表示整数值,而不是用含义模糊的数字来表示。例如,我们可能要编写一个程序来代表星期,有一种思路是使用整数0、1、2和3代表周六、周日、周一和周二,这种方法虽然可以达到目的,但是含义不明确。如果代码中使用了整数值0,则单从字面看并不能知道其代表周日还是周六,使用枚举可以改善这种情况,这显然也增加了代码的可读性。
❑枚举可以使代码更易于维护,有助于确保给变量指定合法的、期望的值。
❑枚举使代码更易于键入。在给枚举类型的实例赋值时,Visual Studio 2010会通过IntelliSense弹出一个包含了可能值的列表框,只需从中选择一个即可,减少了按键次数,从而提高了编码效率。
好了,相信看到这几个优点,大家已经迫不及待想要了解枚举究竟为何方神圣了,本章将会详细介绍枚举这一重要的类型。
14.1 什么是枚举
还是以星期为例,例如,假设要定义一个变量,变量的值表示一周中的每一天,那么该变量就只能有7个有效值——周一到周日,若要定义这些值,不使用枚举的方法是什么呢?一般就是定义7个静态常量,来分别表示周一到周日这7天。例如:
public const int MONDAY=1;
public const int TUESDAY=2;
public const int WEDNESDAY=3;
public const int THURSDAY=4;
public const int FRIDAY=5;
public const int SATURDAY=6;
public const int SUNDAY=7;
现在有了另一种更佳的选择:使用枚举类型。那么究竟什么是枚举呢?枚举由一些命名常量组成,这些常量叫做枚举成员。接下来,我们来看看刚才这个星期的例子使用枚举是如何表示的,如代码清单14-1所示。
代码清单14-1 枚举示例
enum Week
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,//最后一个逗号可选
};//最后一个分号也可选
从上述代码可以看到,我们使用enum关键字来声明一个枚举,enum关键字后就是标识符——枚举的名字,枚举所包含的枚举成员则以逗号作为分隔,位于大括号中。尤其要说明的是,枚举本身可以有访问修饰符,但枚举的成员始终是公共的,不能有任何访问修饰符。其中枚举本身的访问修饰符仅能使用public和internal。
注意 枚举的定义可以与类平级,也可以作为类的成员,但不能放在函数中。
那么,枚举类型的本质是什么呢?枚举类型是值类型,并且隐式地继承自System.Enum类型,但这种继承关系只能由编译器生成,不允许手工这样指定。非常奇妙的事情是,System.Enum本身不是枚举类型,它虽然直接继承自System.ValueType,但本身却是一个引用类型。因此,可以这样说,值类型都是派生自System.ValueType,但派生自System.ValueType的却不全是值类型,这个System.Enum类型就是唯一的特例。
接下来,我们通过对代码清单14-1编译后生成的CIL(Common Intermediate Language,公共中间语言)进行观察,来一探究竟。
首先,我们看看上述代码编译成CIL后的结构是怎样的,包含哪些部分。大家注意观察,看我们可以从中得到哪些重要信息,如图14-1所示。
图 14-1 枚举类型的CIL结构分析
由图14-1可以得到如下信息:
❑枚举类型都是隐式密封的,不允许作为基类派生其他子类;
❑枚举类型均继承自System.Enum类,该类为枚举类型提供用于处理枚举类型值的属性和方法,在程序中适当使用这些属性和方法能简化程序代码,使程序的阅读性更好;
❑枚举类型的枚举成员均为静态,且默认为int(int32)类型。
接下来,我们分别查看一下各个枚举成员的CIL声明代码,按照定义的顺序,先从Monday开始,Sunday最后,CIL代码如代码清单14-2所示。
代码清单14-2 枚举类型中各个枚举成员的CIL代码
Monday:
.field public static literal valuetype ProgrammingCSharp4.Week Monday=int32(0x00000000)
Tuesday:
.field public static literal valuetype ProgrammingCSharp4.Week Tuesday=int32(0x00000001)
Wednesday:
.field public static literal valuetype ProgrammingCSharp4.Week Wedesday=int32(0x00000002)
Thursday:
.field public static literal valuetype ProgrammingCSharp4.Week Thursday=int32(0x00000003)
Friday:
.field public static literal valuetype ProgrammingCSharp4.Week Friday=int32(0x00000004)
Saturday:
.field public static literal valuetype ProgrammingCSharp4.Week Saturday=int32(0x00000005)
Sunday:
.field public static literal valuetype ProgrammingCSharp4.Week Sunday=int32(0x00000006)
由代码清单14-2可以得到如下信息:
❑每个枚举成员均为该枚举类型;
❑每个枚举成员的值类型默认为int32(底层类型),且默认从0(0x00000000)开始,并按照定义顺序依次递增;
❑每个枚举成员均可转换为当前底层类型所表示的值,如0、1、2等,如代码清单14-3所示。
代码清单14-3 获得枚举成员底层的成员值
1 enum Week
2{
3 Monday,//0
4 Tuesday,//1
5 Wedesday,//2
6 Thursday,//3
7 Friday,//4
8 Saturday,//5
9 Sunday//6
10};
11
12 class EnumSample
13{
14 public static void Main()
15{
16 Week w1=Week.Monday;
17 Week w2=Week.Tuesday;
18 Week w3=Week.Wedesday;
19 Week w4=Week.Thursday;
20 Week w5=Week.Friday;
21 Week w6=Week.Saturday;
22 Week w7=Week.Sunday;
23 System.Console.WriteLine("{0},\t{1}",w1,(int)w1);
24 System.Console.WriteLine("{0},\t{1}",w2,(int)w2);
25 System.Console.WriteLine("{0},\t{1}",w3,(int)w3);
26 System.Console.WriteLine("{0},\t{1}",w4,(int)w4);
27 System.Console.WriteLine("{0},\t{1}",w5,(int)w5);
28 System.Console.WriteLine("{0},\t{1}",w6,(int)w6);
29 System.Console.WriteLine("{0},\t{1}",w7,(int)w7);
30}
31}
上述代码的输出如下:
Monday,0
Tuesday,1
Wedesday,2
Thursday,3
Friday,4
Saturday,5
Sunday,6