枚举(Enum)
枚举是由程序员定义的类型,与类或结构一样。
●与结构一样,枚举是值类型,因此直接存储它们的数据,而不是分开存储成引用和数据。
●枚举只有一种类型的成员:命名的整数值常量。
每个枚举类型都有一个底层整数类型,默认是int。
●每个枚举成员都被赋予一个底层类型的常量值。
●在默认情况下,编译器把第一个成员赋值为0,并对每一个后续成员赋值比前一个成员赋值多1。
enum TrafficLight
{
Green,
Yellow,
Red
}
class Program
{
static void Main(string[] args)
{
TrafficLight t1 = TrafficLight.Green;
TrafficLight t2 = TrafficLight.Yellow;
TrafficLight t3 = TrafficLight.Red;
TrafficLight t4 = t3;
Console.WriteLine("{0},\t{1}", t1, (int)t1);
Console.WriteLine("{0},\t{1}", t2, (int)t2);
Console.WriteLine("{0},\t{1}", t3, (int)t3);
Console.ReadKey();
}
}
设置底层类型和显式值
可以把冒号和类型名放在枚举名之后,这样就可以使用int以外的整数类型, 类型可以是任何整数类型。所有成员常量都属于枚举底层类型。
成员常量的值可以是底层类型的任何值。要显示地设置一个成员的值,在枚举声明值的变量名之后使用初始化表达式,尽管不能有重复的名称,但是可以有重复的值:
enum TrafficLight
{
Green=10,
Yellow=15,
Red=15
}
隐式成员编号
一下显示地赋值给任何成员常量。如果不初始化一个成员常量,编译器隐式地给它赋一个值。
●关联到成员名称的值不需要时独特的。
位标志
使用单个字的不同位作为表示一组开/关标志的紧凑方法将其称为标志宇。
步骤:
(1)确定需要多少个位标志,并选择一种有足够多位的无符号类型来保存它。
(2)确定每个位位置代表什么,并给它们一个名词,声明一个选中的整数类型的枚举,每个成员由一个位位置表示。
(3)使用按位或(or)运算符设置保持该为标志的字中的适当的位。
(4)使用按位与(and)运算符,或HasFlag方法解开位标志。
要创建一个带有适当的位标志的字,需要声明一个该枚举类型的变量,并使用按位或运算符设置需要的位。
要判断标志字是否包含特定的位标志集,可以使用枚举类型中的HasFlag布尔方法。在标志字上调用HasFlag方法,并将要检查的位标志作为参数。如果设置了指定的位标志,HasFlag返回true,否则返回false。
HasFlag方法还可以检测多个位标志。
使用按位与运算符
Flags特性
语法:
[Flags]
enum CardDeckSettings:uint{
....
}
Flag特性不会改变计算结果,但却提供了一些方便的特性。
(1)通知编译器、对象浏览器以及其他查看这段代码的工具,该枚举的成员不仅可以用做单独的值。还可以按位标志进行组合。这样浏览器就可以更恰当地解释该枚举的变量。
(2)允许枚举的ToString方法为位标志的值提供更多的格式化信息。ToString方法以一个枚举值为参数,将其与枚举的常量成员相比较。如果与某个成员相匹配,ToString方法返回该成员的字符串名称。
[Flags]
enum CardDeckSettings : uint
{
SingleDeck = 0x01,
LargePictures = 0x02,
FancyNumbers = 0x04,
Animation = 0x08
}
class Program
{
static void Main(string[] args)
{
CardDeckSettings ops;
ops = CardDeckSettings.FancyNumbers;//设置一个标志
Console.WriteLine(ops.ToString());
ops = CardDeckSettings.FancyNumbers | CardDeckSettings.Animation;//设置两个标志
Console.WriteLine(ops.ToString());
Console.ReadKey();
}
}
使用位标志的示例
[Flags]enum CardDeckSettings : uint
{
SingleDeck = 0x01,
LargePictures = 0x02,
FancyNumbers = 0x04,
Animation = 0x08
}
class MyClass
{
bool UseSingleDeck = false;
bool UserBigPics = false;
bool UserFancyNumbers = false;
bool UserAnimation = false;
bool UserAnimationFancyNumbers = false;
public void SetOptions(CardDeckSettings ops)
{
UseSingleDeck = ops.HasFlag(CardDeckSettings.SingleDeck);
UserBigPics = ops.HasFlag(CardDeckSettings.LargePictures);
UserFancyNumbers = ops.HasFlag(CardDeckSettings.FancyNumbers);
UserAnimation = ops.HasFlag(CardDeckSettings.Animation);
CardDeckSettings testFlags = CardDeckSettings.Animation | CardDeckSettings.FancyNumbers;
UserAnimationFancyNumbers = ops.HasFlag(testFlags);
}
public void PrintOption()
{
Console.WriteLine("Option settings:");
Console.WriteLine(" Use Single Deck -{0}", UseSingleDeck);
Console.WriteLine(" Use Large Pictures -{0}", UserBigPics);
Console.WriteLine(" User Fancy Numbers -{0}", UserFancyNumbers);
Console.WriteLine(" Show Animation -{0}", UserAnimation);
Console.WriteLine(" Show Animation and FancyNumbers -{0}", UserAnimationFancyNumbers);
}
}
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
CardDeckSettings ops = CardDeckSettings.SingleDeck | CardDeckSettings.FancyNumbers | CardDeckSettings.Animation;
mc.SetOptions(ops);
mc.PrintOption();
Console.ReadKey();
}
}
关于枚举的补充
枚举只有单一的成员类型:声明的成员常量。
●不能对成员使用修饰符。它们都隐式地具有和枚举相同的可访问性。
●由于成员是常量,即使在每月该枚举类型的变量时它们也可以访问。使用枚举类型名,跟着一个点和成员名。
●枚举是一个独特的类型。比较不同枚举类型的成员会导致编译时的错误。
enum FirstEnum
{
Mem1,
Mem2
}
enum SecondEnum
{
Mem1,
Mem2
}
class Program
{
static void Main(string[] args)
{
if (FirstEnum.Mem1 < FirstEnum.Mem2)//正确,相同的枚举类型
{
Console.WriteLine("True");
}
//if (FirstEnum.Mem1 < SecondEnum.Mem1)//错误,不同的枚举类型
//{
// Console.WriteLine("True");
//}
Console.ReadKey();
}
}
.NET enum类型 (enum就是基于该类型)还包括了一些有用的静态方法:
●GetName方法以枚举类型对象和整数位参数,返回响应的枚举成员的名称;
●GetNames方法以枚举类型对象为参数,返回该枚举中所有成员的全部名称。
enum TrafficLight
{
Green,
Yello,
Red
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Second member of TrafficLight is {0} \n", Enum.GetName(typeof(TrafficLight), 1));
foreach (var name in Enum.GetNames(typeof(TrafficLight)))
{
Console.WriteLine(name);
}
Console.ReadKey();
}
}