Enumeration提供了一些非常炫酷的功能,相信大多数开发人员都不熟悉。这些新功能极大的简化了应用程序开发。
15.1枚举类型
枚举类型(enumerated types)定义了一组“符号名称/值”配对。
以下Color类型定义了一组符号,每个符号都标识一种颜色:
internal enum Color
{
White,//赋值0
Red, //赋值1
Greed,//赋值2
Blue, //赋值3
Orange//赋值4
}
当然,也可以写个程序用0代表白色,1代表红色,以此类推。但不应该将这些数字硬编码到代码中,而应换用枚举类型,因为:
- 枚举类型使程序更容易编写、阅读和维护。
- 枚举类型是强类型的。
每个枚举类型都直接从System.Enum派生,后者从System.ValueType派生。而System.ValueType又从System.Object派生。所以,枚举类型是值类型,可表示成未装箱和已装箱形式。有别于其他值类型,枚举类型不能定义任何方法、属性和事件。
编译枚举类型时,C#编译器会把每个符号转换成类型的一个常量字段。例如,编译器会把前面的Color枚举类型看成以下代码:
C#编译器实际上并不编译这段代码,因为它禁止定义从System.Enum这一特殊类型派生的类型。
枚举类型定义的符号是常量值,所以当编译器一旦发现代码引用了一个枚举类型的符号,就会在编译时用数值替代符号,代码将不再引用定义了符号的枚举类型。
简单地说,枚举类型只是一个结构,其中定义了一组常量字段和一个实例字段。常量字段会嵌入程序集的元数据中,并可通过反射来访问。这意味着在运行时获得与一个枚举类型关联的所有符号及其值。还意味着可以将一个字符串符号转换成对应的数值。这些操作是通过System.Enum基类型来提供的。下面讨论其中的一些操作:
例如,System.Enum类型有一个名为GetUnderlyingType的静态方法,而System.Type类型有一个GetEnumUnderlyingType的实例方法。
public static Type GetUnderlyingType(Type enumType);
public virtual Type GetEnumUnderlyingType();
这些方法返回用于容纳一个枚举类型的值的基础类型。每个枚举类型都有一个基础类型,可以是byte,short,int(最常用,也是C#默认选择的),long。C#要求只能指定基元类型名称,如果使用FCL类型名称(比如Int32),会报错。
我们定义的枚举类型应该与需要调用它的那个类型同级。
以下代码演示了如何声明一个基础类型为byte的枚举类型:
internal enum Color : byte
{
White,
Red,
Greed,
Blue,
Orange
}
static void Main()
{
Console.WriteLine(Enum.GetUnderlyingType(typeof(Color))); //System.Byte
}
C# typeof() 和 GetType()区是什么?
- typeof(x)中的x,必须是具体的类名、类型名称等,不可以是变量名称。
- GetType()方法继承自Object,所以C#中任何对象都具有GetType()方法,它的作用和typeof()相同,返回Type类型的当前对象的类型。
C#编译器将枚举类型视为基元类型,所以,可以用许多熟悉的操作符(==,!=,<,>,<=,>=,+,-,^,&,|,++,--)来操纵枚举类型的实例。
所有这些操作符实际作用于每个枚举类型实例内部的value_实例字段。
给定一个枚举类型的实例,可调用从System.Enum继承的ToString方法:
public static class Program
{
static void Main()
{
//Console.WriteLine(Enum.GetUnderlyingType(typeof(Color)));
Color c = Color.Blue;
Console.WriteLine(c.ToString());//"Blue" 常规格式
Console.WriteLine(c.ToString("G"));//"Blue" 常规格式
Console.WriteLine(c.ToString("D"));//"3" 十进制格式
Console.WriteLine(c.ToString("X"));//"03" 十六进制格式
}
}
internal enum Color : byte
{
White,
Red,
Greed,
Blue,
Orange
}
Format:可调用它格式化一个枚举类型的值:
public static string Format(Type enumType, object value, string format);
Console.WriteLine(Enum.Format(typeof(Color), 3, "G"));//显示"Blue"
GetValues:获取枚举类型中定义的所有符号以及对应的值。
public static Array GetValues(Type enumType);
Color[] colors = (Color[])Enum.GetValues(typeof(Color));
Console.WriteLine("Number of symbols defined:" + colors.Length);
Console.WriteLine("Value\tSymbol\n-----\t------");
foreach (Color c in colors)
{
Console.WriteLine("{0,5:D}\t{0:G}", c);
}
GetName:返回数值的字符串表示。
Enum.GetName(typeof(Color), 3);//"Blue"
GetNames:返回一个String数组,每个符号都代表一个String。
Enum.GetNames(typeof(Color));
// {string[5]}
//[0]: "White"
//[1]: "Red"
//[2]: "Greed"
//[3]: "Blue"
//[4]: "Orange"
Parse, TryParse:将一个符号转换成枚举类型的实例。
public static object Parse(Type enumType, string value, bool ignoreCase);
Color c = (Color)Enum.Parse(typeof(Color), "orange", true); //Orange
Enum.Parse(typeof(Color), "0", true);//White
bool a=Enum.TryParse<Color>("Brown", false, out c);//false, 枚举中没有定义Brown
IsDefine:判断一个值对于一个枚举类型是否合法。
Enum.IsDefined(typeof(Color), "white");//false, 执行的是区分大小写的检查
Enum.IsDefined(typeof(Color), 5);//false, Color枚举类型没有与5对应的符号
15.2位标志
我们可以将位标志当做一种特殊的枚举类型。
FileAttributes类型是基本类型为Int32的枚举类型,其中每一位都反映文件的一项属性。
[Flags] //指示可以将枚举作为位域(即一组标志)处理。
public enum FileAttributes
{
ReadOnly = 1,
Hidden = 2,
System = 4,
Directory = 16,
Archive = 32,
Device = 64,
Normal = 128,
Temporary = 256,
SparseFile = 512,
ReparsePoint = 1024,
Compressed = 2048,
Offline = 4096,
NotContentIndexed = 8192,
Encrypted = 16384,
IntegrityStream = 32768,
NoScrubData = 131072
}
以上FileAttributes类型中,1的二进制为1,2的二进制为10,4的二进制为100。也就是说可以用每个二进制位来确认唯一性,这就是位标志的原理。
public static void Main()
{
//得到可执行文件(.exe文件)的相对路径(如:"...\bin\Debug\ConsoleApplication1.exe")
String file = Assembly.GetEntryAssembly().Location;
//调用System.IO.File类型的GetAttributes方法,会返回FileAttributes类型的一个实例
FileAttributes attributes = File.GetAttributes(file);
//因为二进制1&1才为1,所以只要存在最后的数值一定不为1,判断文件是否隐藏
Console.WriteLine("IS {0} hidden?{1}", file, (attributes & FileAttributes.Hidden) != 0);
//判断文件是否隐藏,换种写法。Enum有一个HasFlag方法,确定当前实例attributes中是否设置了一个或多个位域
Console.WriteLine("IS {0} hidden?{1}", file, attributes.HasFlag(FileAttributes.Hidden));
//将一个文件的属性改为只读和隐藏
File.SetAttributes(file, FileAttributes.ReadOnly | FileAttributes.Hidden);
}