Flags enumerations are used for masking bit fields and doing bitwise comparisons. They are the correct design to use when multiple enumeration values can be specified at the same time. This was quite an official definition and if you are confused then let’s take an example.
For example, theFileShare enumeration contains the ReadWrite value to specify that a shared file can be opened for reading or writing. This shows developers that they can open a shared file for reading or writing, and eliminates the need for them to learn how to specify a combination of enumeration values as a single value.
Let’s take you to the world of Enums where you are allowed to use multiple values rather than using only single value for comparison/storing. To create an Flagged Enumeration you need an attribute [Flags] to be specified on the Enum.
Here are few guidelines while declaring an Enum as flagged.
- Do apply the System.FlagsAttribute to flags enumerations. Do not apply this attribute to simple enumerations.
- Do use powers of two for a flags enumeration's values so they can be freely combined using the bitwise OR operation.
Note: If you do not use powers of two or combinations of powers of two, bitwise operations will not work as expected.
for e.g. Let’s take an example of Identity cards type allowed to fill an application form before applying for a position. So we’ll create an Flagged Enum.
[Flags]
public enum IdentityProofType
{
Passport = 1,
DrivingLicense = 2,
PANCard = 4,
UID = 8,
EmployeeIDCard = 16
}
Now we’ll create a class that keep the information about the Form’s eligibility information. for e.g. AllowedIDs to fill the form:
private IdentityProofType AllowedIDs
= IdentityProofType.Passport | IdentityProofType.UID | IdentityProofType.DrivingLicense;
This is the magic of flagged enumeration now the single field is holding multiple values of the Enumeration. So let’s create some methods in the class EntryForm:
public class EntryForm
{
private IdentityProofType AllowedIDs
= IdentityProofType.Passport | IdentityProofType.UID | IdentityProofType.DrivingLicense;
// Check for eligibility validation
private bool CanApply(IdentityProofType identityProofType)
{
if (AllowedIDs.HasFlag(identityProofType))
{
Console.WriteLine("valid identity provided: {0}", identityProofType);
return true;
}
else
{
return false;
}
}
// Apply check and fill the form if valid
public void FillForm(string username, IdentityProofType identityProofType)
{
if (this.CanApply(identityProofType))
{
Console.WriteLine("Ready to fill the form: {0}", username);
}
else
{
Console.WriteLine("Not a valid id provided by: {0}.", username);
}
}
}
Now Let’s create a test for this class:
EntryForm form1 = new EntryForm();
EntryForm form2 = new EntryForm();
form1.FillForm("Sunny", IdentityProofType.DrivingLicense | IdentityProofType.Passport);
Console.WriteLine("=============");
form2.FillForm("Amit", IdentityProofType.PANCard);
This will result in output:
So now you saw the magic of Flagged Enumerations but ask a question.
How it works??
This works because you previously used multiples of two in you enumeration. Under the covers your enumeration values looks like this (presented as bytes, which has 8 bits which can be 1's or 0's)
Passport: 00000001
DrivingLicense: 00000010
UID: 00000100
PassPort: 00001000
Likewise, after you've set your property AllowedIDs to Passport, DrivingLicense and UId (which values where OR'ed by the pipe |), AllowedIDs looks like this
AllowedIDs: 00001110
So when you retreive the value you are actually bitwise AND'ing the values
myProperties.AllowedIDs: 00001110
IdentityProofType.DrivingLicense: 00000010
-----------------------
00000010 // this is the same as IdentityProofType.DrivingLicense!
Different forms of Flagged Enums
There are different ways you can define a Flagged Enumeration. Since you know that it only allow values to the power of 2. So you can do something like this with your flagged enumeration in case you don’t want to count for the huge collection of Enum.
/// <summary>
/// Flagged with Enum with bitwise shifting
/// </summary>
[Flags]
public enum IdentityProofType : byte
{
None = 0,
Passport = 1 << 0, // 1
DrivingLicense = 1 << 1, // 2
PANCard = 1 << 2, // 4
UID = 1 << 3, // 8
EmployeeIDCard = 1 << 4, // 16
}
Or you can also write this as below:
[Flags]
public enum Options : byte
{
None = 0,
Passport = 1 << 0, // 1
// now that value 1 is available, start shifting from there
DrivingLicense = Passport << 1, // 2
PANCard = DrivingLicense << 1, // 4
UID = PANCard << 1, // 8
EmployeeIDCard = UID << 1 //16
}
Note: If you have notices than there’s a new name introduced in these called None having value 0. It is not allowed to have value starting with 0 in these enum types. But as per the MSDN:
Use None as the name of the flag enumerated constant whose value is zero. You cannot use the None enumerated constant in a bitwise AND operation to test for a flag because the result is always zero. However, you can perform a logical, not a bitwise, comparison between the numeric value and the None enumerated constant to determine whether any bits in the numeric value are set.
Hope you enjoyed reading this. Please leave comments or suggestions.