枚举类型和位标志
枚举类型
internal enum Color
{
White, //赋值0
Red, //赋值1
Blue //赋值2
}
编码时,不应将数字硬编码到代码中,与符号对应的值发生变化,代码简单的重新编译就可,不用对源代码修改,枚举是强类型。
每个枚举类型是从System.Enum派生,后者又从System.ValueType派生,其又从System.Object派生。
编译枚举类型时,C#编译器会把每个符号转换成该类型的一个常量字段,它会把代码当做下面的代码处理:
internal struct Color : System.Enum
{
public const Color White = (Color) 0 ;
public Int32 value__; //包含一个Color变量的值,不能直接引用这个实例字段
}
枚举类型可以看做只是其中定义一系列常量字段和实例字段的结构。常量字段会成为程序集的元数据,通过反射机制来访问,可以在枚举类型关联的所有符号和值之间转换。System.Enum类提供了几个静态方法和实例方法,来操作枚举的实例,而不会使用反射。
public static Type GetUnderlyingType(Type enumType);
返回用于容纳枚举类型值的核心类型。每个枚举都有一个基本类型,可以是byte , sbyte , short , int(默认)等
internal enum Color : byte {}
Console.Write(Enum.GetUnderlyingType(typeof(Color))); // byte
C#编译器把枚举类型当做基元类型来处理,因此可以用==,!=等操作符,还允许显式转换不同的枚举类型的实例,也可显式的或隐式的转换为数值类型。
ToString()
Color c = Color.Blue ;
Console.WriteLine(c.ToString()); //Blue
Console.WriteLine(c.ToString(“G”)); //泛型格式,Blue ,还可用D 十进制格式3,X十六进制03
public static String Format(Type enumType , Object vlaue , String format ) ;
Console.Write(Enum.Format(typeof(Color) , 3 , “G” )); // Blue
public static Array GetValues(Type enumType); // 返回的数组每个元素对应于枚类型中的一个符号名称
public static String GetName(Type enumType , Object value ); // 返回数值对应的字符串表示
public static String[] GetNames(Type enumType ); // 返回一个String数组,每个符号对应一个String
用于查找与符号对应的数值Parse
public static Object Parse(Type enumType , String value);
public static Object Parse(Type enumType , String value , Boolean , ignoreCase);
这个vlaue若可转换为数值,则就会转换成数值型
还有一个
public static Boolean IsDefined(Type enumType , Object value);
可以传入符号值或数值,查找是否在枚举类型中定义了这个值
还有静态方法ToObject,将Byte , int类型实例转换为枚举类型实例
位标志
如System.IO.File类型的GetAttributes方法,返回FileAttributes类型的实例,它是一个类型为Int32的枚举类型,其中每一位(每个bit)都反映了文件的一个属性。
[Flags , Serializable ]
public enum FileAttributes
{
ReadOnly = 0x0001,
Hidden = 0x0002,
System = 0x0004,
……
}
用枚举类型来表示一组可以组合的位标志,枚举类型只表示单个数值,而位标志表示一个集合,其中有些位on,有些位off .
定义用于位标志的枚举类型,应显式的为每个符号指定一个数值,每个符号都有一个单独的位on .经常还定义值为0的None符号,还可定义一此用于组合的符号,
[Flags] //C#编译器允许使用Flags
internal enum Actions
{
None = 0 ,
Read = 0x0001 ,
Write = 0x0002 ,
ReadWrite = Actions.Read | Actions.Write ,
Delete = 0x0004,
……
}
Actions ac = Actions.Read | Actions.Write ; //0x0005
Console.WriteLine(ac.ToString()); // Read , Delete
ToString()试图将数值转换为符号,而0x0005没有对应的符号,但是方法检测到类型上存在Flags属性,就不会将它看做一个单独的数值了,而看做一组位标志。仍可以用G,D,X来格式化。
如果枚举类型没有应用Flags属性时,就查找与该数值匹配的符号,如果应用了,工作过程:
1, 获得枚举类型定义的数值集合,并按降序排列这些数值
2, 每个数值都与枚举实例中的值进行“按位与”操作,如结果等于数值,与该数值关联的字符串就附加到输出字符串之后,该位被除数视为已计算,并会被关闭。不断重复,直到检查完所有数值,或枚举实例的所有位都关闭
3, 之后,如果枚举实例仍然不为0,表明枚举实例中一些处于on状态的位不对应于任何已定义的符号,此时,将枚举实例的数值作为一个字符串返回。
4, 如枚举实例的原始值不为0,就返回各符号之间用逗号分隔的字符串
5, 如果枚举实例的原始值为0,而且枚举类型定义的一个符号的对应值是0,返回这个符号
6, 到这一步时,返回0
如果没有用Flags属性,仍然可用标志F来实现:
Console.WriteLine(actions.ToString(“F”)); // Read , Write
将用逗号分隔的字符串转换为数值Enum.Parse
Actions a = (Actions)Enum.Parse((typeof(Actions), “Write , Read” , false); // 3
Parse方法调用时
1, 从头到尾删除字符中的所有空白字符
2, 如果字符串的第一个字符是数字、加号、减号,该字符串会被认为一个数字,就返回一个枚举实例,其值等于对应数值的字符串
3, 传递的字符串被划分为一个token集合,每个token的空白被去掉
4, 在枚举实例中已定义的符号中查找每个token字符串,没有找到就抛出一个System.ArgumentException异常,找到就对其数值进行“按位与”操作,把它添加到结果中,然后查找下一个符号
5, 查找完,返回结果
另外,不要对位标志使用IsDefined方法,因为传递字符串时,它不会将字符串拆分为token,若传入的是数值,只查找与之匹配的传入的符号,不会应用位标志本身。