《CLR via C#》 枚举和标志位
枚举类型
枚举类型定义了一组“符号名称/值”的配对。且是强类型的。
1enum Color {
2 White, // 赋值0
3 Red, // 赋值1
4 Green, // 赋值2
5}
每个枚举类型都是从System.Enum
派生,后者从System.ValueType
派生,而System.ValueType
从System.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}
注意
枚举类型定义的符号是常量值。所以当编译器发现代码引用了枚举类型的符号时,会在编译时用数值替换符号,代码不再引用定义了符号的枚举类型。这意味着运行时可能并不需要定义了枚举类型的程序集,编译时才需要
每个枚举类型都有一个基础类型,可以是byte
,sbyte
,short
,ushort
,int
(默认),uint
,long
或ulong
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();
用Parse
和TryParse
方法,将符号转换为枚举类型的实例。
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
方法。