枚举介绍,以及枚举成员的组合,判断,移除
关注 1421
枚举
枚举可用于限定选择范围,他包含了一系列基于整数类型(某些语言会提供更多的类型选择)的枚举成员,当你指定函数的参数为某种枚举时,实参就需要是该枚举的某个成员。枚举的常见用途可能是,表示可选择的颜色,表示星期几,表示一年中的月份。
枚举是值类型的,虽然在某些语言的代码中,他表现为类,但一些约束将使其具有确定的存储空间,以符合值类型的要求。
为何使用枚举?
相对于直接使用数字,枚举具有更好的可读性,成员名称可以表达某种含义。相对于使用常量或字符串,枚举更容易维护,在 IDE 的帮助下,修改会更为简单,不容易产生错误。
枚举成员
每一个枚举成员都应该对应一个整数类型的值,这不意味着需要逐个为他们指定,在默认情况下,语言会自动为枚举成员分配一个值,其一般规则为,第一个成员对应0
,之后的成员依次递增1
。
当然,如果有必要,你可以为某个或多个枚举成员指定自己希望的值,而其余成员依然会依据某种规则,获得自动分配的值。
下面的 C# 枚举Color
,成员Black
和Blue
被指定了值,成员Red
和Yellow
根据上一个成员递增了1
。
// 枚举 Color,表示颜色
public enum Color {
// 未设置,0
None,
// 白色,1
White,
// 黑色,10
Black = 10,
// 红色,11
Red,
// 蓝色,100
Blue = 100,
// 黄色,101
Yellow,
}
组合枚举成员
在实际的项目开发中,我们可能会遇到需要组合多个枚举成员的情况,比如,对于表示星期几的枚举,只选择某一天是没有问题的,但如何表示其中两天的组合哪?要完成此目标,可执行如下两个步骤。
首先,需要组合的枚举成员对应的整数应该是0
或2ⁿ
,其中n
从0
开始并依次递增,这样的设计可以确保无论组合是怎样的,组合的结果都有合适的“位置”,不与任何成员重复。
然后,对想要组合的枚举成员,使用或位运算符(|
)即可。其中,任何其他支持组合的枚举成员与0
(值等于0
的成员)组合将等于这些枚举成员自身。
在下面的 C# 代码中,我们使用运算符|
组合了枚举DayOfWeek
的两个成员Monday
和Tuesday
,变量days
显示的输出为3
,不与DayOfWeek
中的任何成员重复。将值为0
的成员None
与days
组合,组合结果与days
相等。
// 组合成员 Monday 和 Tuesday
DayOfWeek days = DayOfWeek.Monday | DayOfWeek.Tuesday;
Console.WriteLine($"days={days}");
// 与 None 组合
Console.WriteLine($"与 None 组合后等于自身?{days == (days | DayOfWeek.None)}");
days=3
与 None 组合后等于自身?True
// 枚举 DayOfWeek,表示星期几
public enum DayOfWeek
{
// 未设置
None = 0,
// 周一
Monday = 1,
// 周二
Tuesday = 2,
// 周三
Wednesday = 4,
// 周四
Thursday = 8,
// 周五
Friday = 16,
// 周六
Saturday = 32,
// 周日
Sunday = 64,
}
判断枚举成员是否包含在枚举成员组合中
在成功实现了多个成员的组合后,如何判断枚举成员是否包含在组合中哪?这个问题较为简单,对成员组合和需要判断的成员,使用与位运算符(&
),并将结果和需要判断的成员比较即可。如果与位运算符(&
)的操作数都是成员组合,那么将判断一个组合中的成员是否同时出现在了另一个组合中。
值为0
的枚举成员,将被认为包含在任何支持组合的枚举成员,或他们的任意组合中。
下面的 C# 函数Rest
,将判断参数dayOfWeek
是否包含了枚举DayOfWeek
的成员Saturday
或Sunday
。值为0
的成员None
包含在成员Monday
与Tuesday
的组合中。
// 函数 Rest 将根据是否是周末来显示信息
void Rest(DayOfWeek dayOfWeek)
{
DayOfWeek weekend = DayOfWeek.Saturday | DayOfWeek.Sunday;
if ((weekend & dayOfWeek) == weekend)
Console.WriteLine("休息两天!");
else if ((DayOfWeek.Saturday & dayOfWeek) == DayOfWeek.Saturday || (DayOfWeek.Sunday & dayOfWeek) == DayOfWeek.Sunday)
Console.WriteLine("周末的味道!");
else
Console.WriteLine("枯燥的味道!");
}
// 传递周一,周五,周六的组合
Rest(DayOfWeek.Monday | DayOfWeek.Friday | DayOfWeek.Saturday);
// 传递周二,周三
Rest(DayOfWeek.Tuesday | DayOfWeek.Wednesday);
// 传递周四,周六,周日的组合
Rest(DayOfWeek.Thursday | DayOfWeek.Saturday | DayOfWeek.Sunday);
// 周一和周二的组合包含了 None
Console.WriteLine($"days 包含 None?{(days & DayOfWeek.None) == DayOfWeek.None}");
周末的味道!
枯燥的味道!
休息两天!
days 包含 None?True
移除枚举成员组合中的枚举成员
通过异或位运算符(^
),你可以将一个或多个枚举成员从成员组合中移除。当然,异或位运算符(^
)还带有或位运算符(|
)的效果,枚举成员会被添加,前提是他们未在组合中出现。
任何其他支持组合的枚举成员移除0
(值等于0
的成员)后依然等于这些枚举成员自身。
在下面的代码中,周二Tuesday
将被异或位运算符(^
)移除,运算的结果为周一Monday
和周三Wednesday
的组合。
DayOfWeek day12 = DayOfWeek.Monday | DayOfWeek.Tuesday;
DayOfWeek day23 = DayOfWeek.Tuesday | DayOfWeek.Wednesday;
// 周二将被移除,周一和周三将被组合
DayOfWeek day13 = day12 ^ day23;
Console.WriteLine($"包含周一?{(day13 & DayOfWeek.Monday) == DayOfWeek.Monday}");
Console.WriteLine($"包含周二?{(day13 & DayOfWeek.Tuesday) == DayOfWeek.Tuesday}");
Console.WriteLine($"包含周三?{(day13 & DayOfWeek.Wednesday) == DayOfWeek.Wednesday}");
// 移除 None
Console.WriteLine($"移除 None 之后等于自身?{(day13 ^ DayOfWeek.None) == day13}");
包含周一?True
包含周二?False
包含周三?True
移除 None 之后等于自身?True
获取相反的枚举成员
对于枚举成员(包括值为0
的成员)或枚举成员的组合,使用取反位运算符(~
)可以获取枚举中这些成员之外的所有枚举成员。
枚举成员或枚举成员组合的取反运算结果可能包含未定义的枚举成员
在一些编程语言中,对枚举成员或枚举成员组合执行取反操作,意味着获取这些成员之外的所有组合状况,这不仅涉及枚举中已经定义的枚举成员,还包括任何未定义的成员,因此取反的运算结果与剩余已定义枚举成员的组合并不相同。
在下面的代码中,我们通过取反位运算符~
,获取了周末以外的枚举成员(包括未定义的成员)的组合,他与成员周一到周五的组合并不相同。
// workdays 是工作日的组合
DayOfWeek workdays = ~(DayOfWeek.Saturday | DayOfWeek.Sunday);
Console.WriteLine($"周一是工作日?{(workdays & DayOfWeek.Monday) == DayOfWeek.Monday}");
Console.WriteLine($"周五是工作日?{(workdays & DayOfWeek.Friday) == DayOfWeek.Friday}");
Console.WriteLine($"相等?{workdays == (DayOfWeek.Monday | DayOfWeek.Tuesday | DayOfWeek.Wednesday | DayOfWeek.Thursday | DayOfWeek.Friday)}");
周一是工作日?True
周五是工作日?True
相等?False