5.2 复杂的变量类型
C#提供了 3 个较复杂(但非常有用)的变量:枚举、结构和数组。
5.2.1 枚举
有时希望变量提取的是一个固定集合中的值。例如,orientation类型可以存储north、south、east或west中的一个值。
此时可以使用枚举类型。枚举就可以完成这个orientation类型的任务:它们允许定义一个类型,其中包含提供的限定值集合中的一个值。所以,需要创建自己的枚举类型 orientation,它可以从上
述4个值中提取一个值。
注意有一个附加的步骤——不是仅仅声明一个给定类型的变量,而是声明和描述一个用户定义的类型,再声明这个新类型的变量。
定义枚举
可以使用enum关键字来定义枚举,如下所示:
enum <typeName> { <value1>, <value2>, <value3>, ... <valueN> }
接着声明这个新类型的变量:
<typeName> <varName>;
并赋值:
<varName> = <typeName>.<value>;
枚举使用一个基本类型来存储,枚举类型可以提取的每个值都存储为该基本类型的一个值,默认情况下该类型为int。在枚举声明中添加类型,就可以指定其他基本类型:
enum <typeName> : <underlyingType> { <value1>, <value2>, <value3>, ... <valueN> }
枚举的基本类型可以是byte、sbyte、short、ushort、int、uint、long和ulong。
在默认情况下,每个值都会根据定义的顺序(从 0 开始),自动赋给对应的基本类型值。这意味着<value1>的值是0,<value2>的值是1,<value3>的值是2等。可以重写这个赋值过程:使用=运算符,并指定每个枚举的实际值:
enum <typeName> : <underlyingType> { <value1> = <actualVal1>, <value2> = <actualVal2>, <value3> = <actualVal3>, ... <valueN> = <actualValN> }
还可以使用一个值作为另一个枚举的基础值,为多个枚举指定相同的值:
enum <typeName> : <underlyingType> { <value1> = <actualVal1>, <value2> = <value1>, <value3>, ... <valueN> = <actualValN> }
没有赋值的任何值都会自动获得一个初始值,这里使用的值是从比上一个明确声明的值大1开始的序列。例如,在上面的代码中,<value3>的值是<value1> + 1。
注意这可能会产生预料不到的问题, 在一个定义(如<value2> = <value1>)后指定的值可能与其他值相同。例如,在下面的代码中,<value4>的值与<value2>相同。
enum <typeName> : <underlyingType> { <value1> = <actualVal1>, <value2>, <value3> = <value1>, <value4>, ... <valueN> = <actualValN> }
当然,如果这正是希望的结果,则代码就是正确的。还要注意,以循环方式赋值可能会产生错误,例如:
enum <typeName> : <underlyingType> { <value1> = <value2>, <value2> = <value1> }
下面看一个示例。其代码定义了一个枚举orientation,然后演示了它的用法。代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Ch05Ex02 { enum orientation : byte { north = 1, south = 2, east = 3, west = 4 } class Program { static void Main(String[] args) { orientation myDirection = orientation.north; Console.WriteLine("myDirection = {0}", myDirection); Console.ReadKey(); } } }
运行结果如下:
退出应用程序,修改代码,如下所示:
byte directionByte; string directionString; orientation myDirection = orientation.north; Console.WriteLine( "myDirection = {0}", myDirection ); directionByte = ( byte )myDirection; directionString = Convert.ToString( myDirection ); Console.WriteLine( "byte equivalent = {0}", directionByte ); Console.WriteLine( "string equivalent = {0}", directionString ); Console.ReadKey();
运行结果如下:
首先要注意的是,类型定义代码放在名称空间 Ch05Ex02,而没有与其余代码放在一起。这是因为在运行期间,定义代码并不是像执行应用程序中的代码那样一行一行地执行。应用程序是从已经习惯的位置开始执行的,并可以访问新类型,因为它属于同一个名称空间。
注意这里必须使用显式转换。即使 orientation 的基本类型是byte,仍必须使用(byte)强制类型转换,把myDirection的值转换为byte类型。
如果要将 byte 类型转换为 orientation,也同样需要进行显式转换。例如,可以使用下述代码将byte变量myByte转换为orientation,并把这个值赋给myDirection:
myDirection = (orientation)myByte;
这里必须小心,因为并不是所有byte类型变量的值都可以映射为已定义的orientation值。
要获得枚举的字符串值,可以使用Convert.ToString()。
使用(string)强制类型转换是行不通的,因为需要进行的处理并不仅仅是把存储在枚举变量中的数据放在string变量中,而是更复杂一些。另外,还可以使用变量本身的ToString()命令。下面的代码与使用Convert.ToString()的效果相同:
directionString = myDirection.ToString();
也可以把 string 转换为枚举植,但其语法稍复杂一些。有一个特定的命令用于此类转换,即Enum.Parse(),其用法如下:
(enumerationType)Enum.Parse(typeof(enumerationType), enumerationValueString);
它使用了另一个运算符 typeof,可以得到操作数的类型。对 orientation 类型使用这个命令,如下所示:
string myString = "north"; orientation myDirection = (orientation)Enum.Parse(typeof(orientation),
当然,并非所有的字符串值都会映射为一个 orientation 值。如果传送的一个值不能映射为枚举值中的一个,就会产生错误。