简体   繁体   English

&在C#中具有枚举值的运算符

[英]& operator with enum values in C#

I have following code and Console.WriteLine is returning Bottom even though Bottom is not in both enum expressions. 我有以下代码,即使两个枚举表达式中都不存在Bottom ,但Console.WriteLine返回Bottom

Question

What is the logic behind returning Bottom in code snippet given below? 在下面给出的代码片段中返回Bottom背后的逻辑是什么? My understanding of & operator is that it returns the common part, but in this case there is nothing common between the two enum expressions. 我对&运算符的理解是,它返回公共部分,但是在这种情况下,两个枚举表达式之间没有任何公共之处。

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
};

You assign values to the enums, and the operators | 您为枚举赋值,运算符| and & work on the enum values, like they would work on the corresponding values. &处理枚举值,就像它们将处理对应的值一样。

You have set the values of the enum values yourself, and you have not set them orthogonal . 您自己设置了枚举值的值,并且没有将它们设置为正交 Since integers are in fact bitstrings (with fixed length), you can see it as a 32-dimensional vector (with every vector element having domain {0,1} ). 由于整数实际上是位串(具有固定长度),因此您可以将其视为32维向量(每个向量元素都具有域{0,1} )。 Since you defined for instance Bottom as 3 , it means that Bottom is actually equal to Right | Top 由于您将实例Bottom定义为3 ,这意味着Bottom实际上等于Right | Top Right | Top , since: Right | Top ,因为:

Right | Top
    1 |   2  (integer value)
   01 |  10  (bitwise representation)
   11        (taking the bitwise or)
Bottom

So that means that if you write & , this is a bitwise AND , and | 因此,这意味着,如果您编写& ,则这是按位AND ,而| , is a bitwise OR on the values of the enum values. ,是按位或在枚举值的

So if we now evaluate it, we get: 因此,如果现在评估它,我们将得到:

(Orientations.Left|Orientations.Bottom) & (Orientations.Right|Orientations.Top)
(0                | 3                 ) & (1                 | 2)
3                                       & 3
3
Orientations.Bottom

If you want to define four orthogonal values , you need to use powers of two : 如果要定义四个正交值 ,则需要使用两个的幂

[Flags]
public enum Orientations {
    Left = 1,    // 0001
    Right = 2,   // 0010
    Top = 4,     // 0100
    Bottom = 8   // 1000
};

Now you can see the enum as four different flags, and and the & will create the intersection, and | 现在,您可以看到枚举是四个不同的标志,并且&将创建交集,并且| the union of the flags. 旗帜的联合。 In comment the bitwise representation of each value is written. 在注释中,写入每个值的按位表示。

As you can see, we can now see Left , Right , Top and Bottom as independent elements, since we can not find a monotonic bitwise construction ( to combine Left , Right and Top to construct Bottom (except negation). 如您所见,我们现在可以将LeftRightTopBottom视为独立元素,因为我们找不到单调的按位构造(将LeftRightTop以构造Bottom (除法除外)。

In order for flag enums to work as expected, the enum constants need to be powers of 2. 为了使flag枚举能够按预期工作,枚举常量必须为2的幂。

In your example the binary values look like this (I show 4 bits only for sake of simplicity) 在您的示例中,二进制值如下所示(为简单起见,我仅显示4位)

Left   = 0                     0000
Right  = 1                     0001
Top    = 2                     0010
Bottom = 3                     0011
Left | Right | Top | Bottom =  0011 which is 3 or Bottom again 

If you choose powers of 2 you get 如果选择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 

Ie, with powers of 2, different bits are set and therefore they combine neatly with the bitwise OR operator (|). 即,使用2的幂时,会设置不同的位,因此它们与按位OR运算符(|)巧妙地组合在一起。

Since C# 7.0 you can use binary literals 从C#7.0开始,您可以使用二进制文字

[Flags]
public enum Orientations {
    Left   = 0b0001,
    Right  = 0b0010,
    Top    = 0b0100,
    Bottom = 0b1000
};

In previous versions of C# you can also use the left shift operator to get powers of 2 在以前的C#版本中,您还可以使用左移运算符获得2的幂

[Flags]
public enum Orientations {
    Left   = 1 << 0,
    Right  = 1 << 1,
    Top    = 1 << 2,
    Bottom = 1 << 3
};

It is a good practice to also include the enum constant None = 0 because enum fields are initialized to default(MyEnum) == 0 , otherwise resulting in a value having no corresponding enum constant. 最好还包含枚举常量None = 0因为枚举字段被初始化为default(MyEnum) == 0 ,否则会导致没有对应的枚举常量的值。

You can also create new combined enum values like this 您也可以像这样创建新的合并枚举值

[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
};

Note that every enum has an implicit conversion from 0. Therefore you could do this test 请注意,每个枚举都有一个从0的隐式转换。因此,您可以执行此测试

if((myOrientations & Orientations.Vertical) != 0) {
    // We have at least a Top or Bottom orientation or both
}

It is & and | 是&和| bitwise operation. 按位运算。 In the example: 在示例中:

(( Orientations.Left | Orientations.Bottom) & 
                     (Orientations.Right| Orientations.Top))

Will replace with 将替换为

((0 | 3) & (1 | 2)) with in bit (show only last 3 bit):
((000 |011) & (001 | 010))
= (011 & 011)
= 011

011 is 3 in int value which is Orientations.Bottom value. 011的int值是3,即Orientations.Bottom值。 Therefore, It is always returning Orientations.Bottom. 因此,它总是返回Orientations.Bottom。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM