15.枚举类型和位标志
15.1枚举类型
枚举类型Enum直接从System.Enum派生,后者从System.ValueType派生,而后者从System.Object派生,所以,枚举类型是值类型,但和其他值类型不一样,枚举类型不能定义任何方法(不过可以通过扩展方法模拟添加方法,15.3节会讲)、属性或事件。
枚举类型要和另一个类型结合使用,经常作为需要它的类型里的方法参数、返回类型、属性和字段使用。
枚举类型建议与需要它的类型同级,而不是嵌套定义在需要它的类型中。
枚举类型举例:
internal enum Color // 枚举类型的基本类型默认为System.Int32
{
// 以下的都为常量(const)字段,都叫做符号
White, // 编译器将White看成这种代码:public const Color White = (Color) 0;,编译时用数值替换符号
Red,
Green,
Blue,
Orange
}
Enum类型提供了实例方法ToString()等,还提供了静态方法GetValues()(等价于Type类型提供的GetEnumValues())、GetNames()(等价于Type类型提供的GetEnumNames())等,举例:
static void Main(string[] args)
{
Color c = Color.Blue; // 初始化枚举类型的对象
Console.WriteLine(c.ToString()); // 输出Blue
// 通过Enum提供的静态方法GetValues,来获得符号的名字
Color[] colors = (Color[])Enum.GetValues(typeof(Color)); // GetValues返回一个Array
foreach (var color in colors)
Console.WriteLine(color);
// 通过泛型方法来优化上述代码
colors = GetValues<Color>(); // 下方定义了该泛型方法
foreach (var color in colors)
Console.WriteLine(color);
// 通过Type提供的实例方法GetEnumValues,来获得符号的名字
colors = (Color[])c.GetType().GetEnumValues();
foreach (var color in colors)
Console.WriteLine(color);
// 也可以通过Enum提供的静态方法GetNames或Type提供的实例方法GetNames,来获得符号的名字
string[] names = Enum.GetNames(typeof(Color)); // names = c.GetType().GetEnumNames();
foreach (var name in names)
Console.WriteLine(name);
}
public static TEnum[] GetValues<TEnum>() where TEnum : struct
{
return (TEnum[])Enum.GetValues(typeof(TEnum));
}
15.2位标志
定义含有位标志的枚举类型时,应显示地为每个符号分配一个数值,每个符号都有单独的一个位处于on状态(也就是二进制表示中有一位为1),经常要定义一个值为0的None符号,还经常定义一些符号来代表常见的位组合(比如下方的ReadWrite)。
[Flags]
internal enum Actions
{
None = 0,
Read = 0x0001, // 用十六进制表示,每个独立的符号都是2的整数次方
Write = 0x0002,
ReadWrite, // ReadWrite是符号的组合,等价于“Read|Write”,可理解为“0x0001 | 0x0002 = 0x0003”
Delete = 0x0004,
Query = 0x0008,
Sync = 0x0010
}
// 在Main函数里:
Actions actions = Actions.Write | Actions.Delete; // 0x0006,没有对应的符号,但由于Actions上存在[Flags]特性
Console.WriteLine(actions.ToString()); // 所以,ToString方法把0x0006视为一组位标志,输出为:Write, Delete
// 如果Actions上没有[Flags]特性,输出就为6
上面讲的是如何将数值转换为标志字符串(以逗号分隔的符号字符串),下面讲的是如何将标志字符串转换为数值,用Enum提供的静态方法Parse和TryParse:
Console.WriteLine((int)Enum.Parse(typeof(Actions), "Delete", true)); // 第三个参数表示:是否辨别大小写, 输出4
Actions a = (Actions)Enum.Parse(typeof(Actions), "Write", true);
Console.WriteLine(a); // 输出:Write
15.3向枚举类型添加方法
利用C#的扩展方法模拟向枚举类型添加方法:
internal static class ActionsExtensionMethods
{
public static Actions Set(this Actions flags, Actions setFlags) // 向flags字符里添加setFlags字符
{
return flags | setFlags;
}
}
// 在Main函数里:
Actions ac = Actions.Sync;
ac = ac.Set(Actions.Read);
Console.WriteLine(ac.ToString()); // 输出:Read, Sync