我有以下代码并Console.WriteLine返回,Bottom即使Bottom不在两个枚举表达式中.
题
在下面给出的代码片段中返回Bottom背后的逻辑是什么?我对&运算符的理解是它返回公共部分,但在这种情况下,两个枚举表达式之间没有任何共同之处.
void Main()
{
Console.WriteLine(( Orientations.Left | Orientations.Bottom) &
(Orientations.Right| Orientations.Top));//returns Bottom
}
[Flags]
public enum Orientations {
Left = 0, Right= 1, Top=2, Bottom =3
};
Run Code Online (Sandbox Code Playgroud)
你赋值的枚举,以及运营商|和&上枚举值的工作,像他们将在相应的值工作.
您自己设置了枚举值的值,但尚未将它们设置为正交值.由于整数实际上是位串(具有固定长度),因此您可以将其视为32维向量(每个向量元素都具有域{0,1}).既然你的实例定义Bottom为3,这意味着Bottom实际上是等于Right | Top,因为:
Right | Top
1 | 2 (integer value)
01 | 10 (bitwise representation)
11 (taking the bitwise or)
Bottom
Run Code Online (Sandbox Code Playgroud)
这意味着如果你写&,这是一个按位AND,并且|是枚举值的值的按位OR.
所以,如果我们现在评估它,我们得到:
(Orientations.Left|Orientations.Bottom) & (Orientations.Right|Orientations.Top)
(0 | 3 ) & (1 | 2)
3 & 3
3
Orientations.Bottom
Run Code Online (Sandbox Code Playgroud)
如果要定义四个正交值,则需要使用两个幂:
[Flags]
public enum Orientations {
Left = 1, // 0001
Right = 2, // 0010
Top = 4, // 0100
Bottom = 8 // 1000
};Run Code Online (Sandbox Code Playgroud)
现在,您可以将枚举看作四个不同的标志,并且&将创建交集和|标志的并集.在注释中,写入每个值的按位表示.
正如你所看到的,我们现在可以看到Left,Right,Top并Bottom作为独立的元素,因为我们无法找到一个单调的逐位结构(结合Left,Right并Top构建Bottom(除了否定).
为了使标志枚举按预期工作,枚举常量需要是 2 的幂。
在您的示例中,二进制值如下所示(为了简单起见,我仅显示 4 位)
Left = 0 0000
Right = 1 0001
Top = 2 0010
Bottom = 3 0011
Left | Right | Top | Bottom = 0011 which is 3 and equal to Bottom
Run Code Online (Sandbox Code Playgroud)
如果您选择 2 的幂,则恰好设置一位,您将得到
Left = 1 = 2^0 0001
Right = 2 = 2^1 0010
Top = 4 = 2^2 0100
Bottom = 8 = 2^3 1000
Left | Right | Top | Bottom = 1111
Run Code Online (Sandbox Code Playgroud)
即,对于 2 的幂,设置了不同的位,因此它们与按位或运算符 (|) 巧妙地结合在一起。
从 C# 7.0 开始,您可以使用二进制文字
[Flags]
public enum Orientations {
Left = 0b0001,
Right = 0b0010,
Top = 0b0100,
Bottom = 0b1000
};
Run Code Online (Sandbox Code Playgroud)
在以前版本的 C# 中,您还可以使用左移运算符来获取 2 的幂
[Flags]
public enum Orientations {
Left = 1 << 0,
Right = 1 << 1,
Top = 1 << 2,
Bottom = 1 << 3
};
Run Code Online (Sandbox Code Playgroud)
最好还包含枚举常量,None = 0因为枚举字段被初始化为default(MyEnum) == 0,否则会导致值没有相应的枚举常量。
您还可以像这样创建新的组合枚举值
[Flags]
public enum Orientations {
None = 0,
Left = 1 << 0,
Right = 1 << 1,
Top = 1 << 2,
Bottom = 1 << 3,
Horizontal = Left | Right,
Vertical = Top | Bottom,
All = Horizontal | Vertical
};
Run Code Online (Sandbox Code Playgroud)
请注意,每个枚举都有从 0 开始的隐式转换。因此您可以进行此测试
if((myOrientations & Orientations.Vertical) != 0) {
// We have at least a Top or Bottom orientation or both
}
Run Code Online (Sandbox Code Playgroud)