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 see an example.
For example, the FileShare 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 a single value for comparison/storing. To create an Flagged Enumeration you need the "[Flags]" attribute to be specified on the Enum.
Here are a few guidelines for 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 for example Let's see an example of Identity cards type allowed to fill in an application form before applying for a position. So we'll create a Flagged Enum.
[Flags]
public enum IdentityProofType
{
Passport = 1,
DrivingLicense = 2,
PANCard = 4,
UID = 8,
EmployeeIDCard = 16
}
Now we'll create a class that maintains the information about the Form's eligibility information. For example AllowedIDs to fill in the form:
private IdentityProofType AllowedIDs
= IdentityProofType.Passport | IdentityProofType.UID | IdentityProofType.DrivingLicense;
This is the magic of flagged enumeration. Now the single field holds 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 the output:
So now you saw the magic of Flagged Enumerations but then you may ask a question.
How does it work?
This works because you previously used multiples of two in the enumeration. Under the covers your enumeration values looks like this (presented as bytes, that has 8 bits that 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 retrieve the value you are actually bitwise AND'ing the values:
myProperties.AllowedIDs: 00001110
IdentityProofType.DrivingLicense: 00000010
-----------------------
00000010 // this is the same as IdentityProofType.DrivingLicense!
Various forms of Flagged Enums
There are various ways you can define a Flagged Enumeration. Since you know that it only allows values to be powers of 2. So you can do something like this with your flagged enumeration in case you don't want to do the counting youself for a huge collection of Enums.
/// <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 noticed then 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.