第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

图 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