《CLR via C#》 枚举和标志位

枚举类型

枚举类型定义了一组“符号名称/值”的配对。且是强类型的。

1enum Color {
2    White,  // 赋值0
3    Red,    // 赋值1
4    Green,  // 赋值2
5}

每个枚举类型都是从System.Enum派生,后者从System.ValueType派生,而System.ValueTypeSystem.Object派生。所以枚举是值类型,但枚举不能定义任何方法、属性或事件。不过可以利用扩展方法模拟向枚举类型添加方法

1public static class EnumExtension {
2    public static bool Extension(this Color color) {
3        // ...
4    }
5}

编译器编译枚举类型时,把每个符号转换成类型的一个常量字段。类似于如下代码

1// 伪代码
2public struct Color : System.Enum {
3    public const Color White = (Color) 0;
4    public const Color Red = (Color) 1;
5    public const Color Green = (Color) 2;
6    // 以下是一个公共实例字段,包含Color变量的值,不能写代码来直接引用该字段
7    public int value__;
8}

注意

枚举类型定义的符号是常量值。所以当编译器发现代码引用了枚举类型的符号时,会在编译时用数值替换符号,代码不再引用定义了符号的枚举类型。这意味着运行时可能并不需要定义了枚举类型的程序集,编译时才需要

每个枚举类型都有一个基础类型,可以是bytesbyteshortushortint(默认),uintlongulong

1// 定义一个基础类型位byte的枚举类型
2enum Color : byte {
3    White,
4    Red,
5    Green,
6}

枚举类型的方法

可用以下方法获取基础类型的Type

1public static Type GetUnderlyingType(Type enumType);
2public Type GetEnumUnderlyingType();

获取枚举中所有的符号名称。

1public static Array GetValues(Type enumType);
2public Array GetEnumValues();
3// 建议如下编码,保证编译时的类型安全
4public static TEnum[] GetEnumValues<TEnum>() where TEnum : struct {
5    return (TEnum[]) Enum.GetValues(typeof(TEnum));
6}

获取枚举类型的符号String。

1// 返回数值的字符串表示
2public static String GetName(Type enumType, Object value);
3public String GetEnumName(Object value);
4
5// 返回一个String数组,枚举中每个符号都对应一个String
6public static String[] GetNames(Type enumType);
7public String[] GetEnumNames();

ParseTryParse方法,将符号转换为枚举类型的实例。

1public static Object Parse(Type enumType, String value);
2public static Object Parse(Type enumType, String value, Boolean ignoreCase);
3public static Boolean TryParse<TEnum>(String value, out TEnum result) where TEnum : struct;
4public static Boolean TryParse<TEnum>(String value, Boolean ignoreCase, out TEnum result) where TEnum : struct;

IsDefined方法判断数值对于枚举类型是否合法。此方法执行效率很慢,因为用了反射

1public static Boolean IsDefined(Type enumType, Object value);
2pulic Boolean IsEnumDefined(Object value);

注意

C#允许将枚举类型的实例显式转型位不同的枚举类型或数值类型。

提示

枚举类型通常于需要它的类同级。原因很简单,就是减少代码的录入量,是开发的工作变的更轻松。所以除非担心名称冲突,否则你定义的枚举类型应该和需要它的类型同级。

位标志

定义用于标识为标志的枚举类型时,应该显式为每个符号分配一个数值。通常,每个符号都有单独的一个位处于on状态。还可以定义一些符号来代表常见的位组合。Flags特性用于在调用ToString时识别为位组合。如果数值有一个位不能映射到一个符号,返回的字符串只包含一个代表原始数值的十进制数。

1[Flags]
2public enum Color {
3    White = 1,
4    Red = 2,
5    Green = 4,
6}
7
8Color colors = Color.Red | Color.Green;
9Console.WriteLine(colors.ToString());   // "Red, Green"

注意

避免使用HasFlag方法。由于它获取Enum类型的参数会装箱。

注意

不要对位标志枚举类型使用IsDenfined方法。