枚举为标志
FlagsAttribute
可以应用于枚举,改变 ToString()
的行为以匹配枚举的性质:
[Flags]
enum MyEnum
{
//None = 0, can be used but not combined in bitwise operations
FlagA = 1,
FlagB = 2,
FlagC = 4,
FlagD = 8
//you must use powers of two or combinations of powers of two
//for bitwise operations to work
}
var twoFlags = MyEnum.FlagA | MyEnum.FlagB;
// This will enumerate all the flags in the variable: "FlagA, FlagB".
Console.WriteLine(twoFlags);
因为 FlagsAttribute
依赖于枚举常量是 2(或它们的组合)的幂,并且枚举值最终是数值,所以你受到基础数值类型的大小的限制。你可以使用的最大可用数字类型是 UInt64
,它允许你指定 64 个不同(非组合)标志枚举常量。enum
关键字默认为基础类型 int
,即 Int32
。编译器将允许声明宽于 32 位的值。这些将在没有警告的情况下环绕并导致两个或更多具有相同值的枚举成员。因此,如果枚举是为了容纳超过 32 个标志的位集,则需要明确指定更大的类型:
public enum BigEnum : ulong
{
BigValue = 1 << 63
}
尽管标志通常只有一个位,但它们可以组合成命名的集合以便于使用。
[Flags]
enum FlagsEnum
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
Default = Option1 | Option3,
All = Option1 | Option2 | Option3,
}
为了避免拼写出 2 的幂的十进制值,左移运算符(<<) 也可用于声明相同的枚举
[Flags]
enum FlagsEnum
{
None = 0,
Option1 = 1 << 0,
Option2 = 1 << 1,
Option3 = 1 << 2,
Default = Option1 | Option3,
All = Option1 | Option2 | Option3,
}
从 C#7.0 开始,也可以使用二进制文字 。
要检查枚举变量的值是否设置了某个标志,可以使用 HasFlag
方法。假设我们有
[Flags]
enum MyEnum
{
One = 1,
Two = 2,
Three = 4
}
和一个 value
var value = MyEnum.One | MyEnum.Two;
使用 HasFlag
,我们可以检查是否设置了任何标志
if(value.HasFlag(MyEnum.One))
Console.WriteLine("Enum has One");
if(value.HasFlag(MyEnum.Two))
Console.WriteLine("Enum has Two");
if(value.HasFlag(MyEnum.Three))
Console.WriteLine("Enum has Three");
我们也可以迭代 enum 的所有值来获取所有设置的标志
var type = typeof(MyEnum);
var names = Enum.GetNames(type);
foreach (var name in names)
{
var item = (MyEnum)Enum.Parse(type, name);
if (value.HasFlag(item))
Console.WriteLine("Enum has " + name);
}
要么
foreach(MyEnum flagToCheck in Enum.GetValues(typeof(MyEnum)))
{
if(value.HasFlag(flagToCheck))
{
Console.WriteLine("Enum has " + flagToCheck);
}
}
这三个例子都将打印出来:
Enum has One
Enum has Two