I have following code and Console.WriteLine
is returning Bottom
even though Bottom is not in both enum expressions.
Question
What is the logic behind returning Bottom in code snippet given below? 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}
). Since you defined for instance Bottom
as 3
, it means that Bottom
is actually equal to Right | Top
Right | Top
, since:
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 |
, 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 = , // 0001
Right = , // 0010
Top = , // 0100
Bottom = // 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).
In order for flag enums to work as expected, the enum constants need to be powers of 2.
In your example the binary values look like this (I show 4 bits only for sake of simplicity)
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
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 (|).
Since C# 7.0 you can use binary literals
[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
[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.
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
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. Therefore, It is always returning Orientations.Bottom.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.