Photo by Marius Niveri on Unsplash
In some cases we may want to store multiple states in the same object, or more generally to retain some elements that might occur in combination.
Lets take a Calendar as an example, in which a CalendarDay could be either Opened or Closed.
When the CalendarDay is Open it could also be Booked by a customer or Blocked by the administrator of the calendar. In those cases it would be nice to retain both Opened AND Booked or Opened AND Blocked states in the same object (a property of the CalendarDay) and there are many approaches to this problem.
We could of course use an array or multiple bool properties (IsOpen, IsBooked, IsBlocked etc..), or we can also use a clever trick with C# flags where an enumeration can be treated as a bit field that provide as a much more easy way of achieving this outcome.
How flags work, what is a bit field.
Flags are Enumerations with a FlagsAttribute in their declaration. An example can be seen here.
[Flags]
public enum CalendarDayState
{
None = 0,
Open = 1,
Closed = 2,
Blocked = 4,
Booked = 8,
Other = 16
}
The FlagsAttribute can only be applied in Enumerations.
The most important element in the above code is the integer initialization, which is in power of 2. This is key for the enumeration to work as a flag and we will explain why.
First, we have to see how those decimal numbers are represented in binary:
0 => 00000
1 => 00001 2^0
2 => 00010 2^1
4 => 00100 2^2
8 => 01000 2^3
16 => 10000 2^4
Now we can see that the position of ‘1’ in each number does not overlap with the others. This gives us with a special advantage when we begin to do logical operations between them (AND, OR, XOR etc.).
For example if 00001 is the Open state and 00100 is the Blocked state, then we can represent a combination of those states with 00101.
Declare a variable bit field enumeration
With the above example we can use a variable to store the combined Enum values. For example we can store both Open and Booked value like this:
var state = CalendarDayState.Open | CalendarDayState.Booked;
We used the | (OR) logical operator in order to apply bitwise operation between 00001 (Open) and 01000 (Booked). The result of this would be 01001, that is 9 in decimal and that means that the state variable has both Open and Booked values inside it.
Then we can check for example, if the variable has the Open state in it with the help of the AND logical operation:
Console.WriteLine("Has Open: " + ((state & CalendarDayState.Open) == CalendarDayState.Open));
In the above example, first we do an AND (&) logical operation between 01001 and 00001. This will result to 00001 (Open). Compering the result to the Open value will result to true.
In addition, .NET has the HasFlag() method that checks if the variable has a specific Enum value.
Console.WriteLine("Has Open: " + state.HasFlag(CalendarDayState.Open));
This also results to true.
Add Enum value the state variable
In order to add a new Enum value to the already existing values in the state variable we will use the | operator again like this.
var state = CalendarDayState.Open | CalendarDayState.Booked;
state |= CalendarDayState.Other;
This will add the ‘Other’ State into state object:
Open: True
Closed: False
Blocked: False
Booked: True
Other: True
Remove an Enum value from the state variable
if we want to remove a value from the state variable we will use the XOR (^) operator like this:
var state = CalendarDayState.Open | CalendarDayState.Booked | CalendarDayState.Other;
state ^= CalendarDayState.Other;
Console.WriteLine("Open: " + state.HasFlag(CalendarDayState.Open));
Console.WriteLine("Closed: " + state.HasFlag(CalendarDayState.Closed));
Console.WriteLine("Blocked: " + state.HasFlag(CalendarDayState.Blocked));
Console.WriteLine("Booked: " + state.HasFlag(CalendarDayState.Booked));
Console.WriteLine("Other: " + state.HasFlag(CalendarDayState.Other));
The result is the following:
Open: True
Closed: False
Blocked: False
Booked: True
Other: False
In the previous example, the decimal value the variable state has initially (Open | Booked | Other) is 25. This is 11001 in binary. The ‘Other’ has 10000 in binary.
If we do XOR between them we will have the following result:
11001 XOR 10000 = 01001
01001 is Open | Booked.
In this way we removed the ‘Other’ state from the variable.
Another way is to invert all the bits from the Enum value and use the AND (^) operator like this:
state &= ~CalendarDayState.Other;
4 Comments
Great content! Keep up the good work!
Nice examples
Thanks!
Howdy! Do you know if they make any plugins to safeguard against hackers?
I’m kinda paranoid about losing everything I’ve worked hard on. Any suggestions?