Is it ok to add an "All" item to a Flags enum? - c#

If I have an enum with multiple values which can be present at the same time, I create a Flags enum:
[Flags]
public enum Foo
{
None = 0,
A = 1,
B = 2,
C = 4,
D = 8
}
If I now want to pass the fact that every value is set I would have to do something like this:
Bar bar = new Bar(Foo.A | Foo.B | Foo.C | Foo.D);
Would it be considered bad practice/harmful/blasphemy to add an additional element All?
All = 15
This would save some space and time when there are a lot of values and passing them all is a common scenario.
As far as I understand the mechanics of flags enums (=bitfields), this should work. Are there any side effects I am missing or other reasons why you should not do that?

You can do that. But maybe you shoudn't use the value 15, but
All = A | B | C | D

There is a dangerous gotcha here where if you change All but the calling components are not recompiled, they will send the old All. If this is fine with you than so be it.

Using bitwise operations is much easier to read
[Flags]
public enum MyEnum
{
None = 0,
First = 1 << 0,
Second = 1 << 1,
Third = 1 << 2,
Fourth = 1 << 3,
All = ~(-1 << 4)
}

The most likely place this will go wrong is
[Flags]
public enum Foo
{
None = 0,
A = 1,
B = 2,
C = 4,
D = 8
E = 16
All = 15
}
Us propeller heads tend to be microfocused, added E job done. oops, oh dear, damn....
And then you take the All idea one step further and feel a need for AllbutC.

Related

Is there a way to tell if an enum has exactly one, multiple or no flags set?

I have an enum defined like that:
[Flags]
public enum Orientation
{
North = 1,
North_East = 2,
East = 4,
South_East = 8,
South = 16,
South_West = 32,
West = 64,
North_West = 128
}
Is there a generic way to tell if exactly one flag is set, multiple or none?
I don't care for what the value of the enum is, I just want to know how many flags are set.
This is not a duplicate for counting the number of bits. If I initialize the enum like this and count the number of bits I get 10. But the number of set flags would be 8.
GeographicOrientation go = (GeographicOrientation) 1023;
You can determine this with a simple bit trick after converting the value to int:
int v = (int)enumValue;
If v == 0, then no flags are set
Otherwise, if ((v-1)&v) == 0, then exactly one flag is set
Otherwise, multiple flags are set.
The only tricky one is #2. Here is an explanation: consider a binary number with exactly one bit set to 1. Then subtracting 1 would make the following change:
0000010000000
- 1
-------------
0000001111111
All zeros following the lone 1 become 1s, 1 becomes zero, and the rest of the bits remain the same. AND-ing v and v-1 produces zero, because there is no pair of 1s in the same position between the two numbers.
When there are two or more 1s, the bits to the left of the lone 1 will remain unchanged. Therefore, at least one position will have a 1 in the result of bitwise AND.
you can use this code :
var item = Orientation.North | Orientation.South;
int i = 0;
foreach (Orientation e in Enum.GetValues(typeof(Orientation)))
if(item.HasFlag(e))
i++;
Console.WriteLine(i);
var test = Orientation.North;
var flagCount = GetFlagCount(test);
public int GetFlagCount(Enum testValue)
{
return Enum.GetValues(testValue.GetType()).Cast<Enum>().Count(testValue.HasFlag);
}
If you are looking for the "shortest" way:
Orientation o = Orientation.East | Orientation.West; // o.ToString() = "East, West"
var c = o.ToString().Split().Count();
or even shorter:
var c = (o + "").Split().Count();
Update
To support values above 255, you can use any of those ugly hacks:
Orientation o = (Orientation) 1023;
var c = ((Orientation)(byte)o + "").Split().Count();
c = ((Orientation)((int)o & 255) + "").Split().Count();
or just define the enum as byte:
[Flags]
public enum Orientation : byte
{
North = 1,
North_East = 2,
East = 4,
South_East = 8,
South = 16,
South_West = 32,
West = 64,
North_West = 128
}
Update 2
I personally wouldn't use the string method in production code especially when just a bit count is needed.
Anyway, I just thought of another hack just for fun. Base 2 log will return a whole number when one bit is set, -Infinity when 0, and anything else when more than one bit is set. For Example
Math.Log(0, 2 ) // -Infinity
Math.Log(0, 64) // 6.0
Math.Log(0, 65) // 6.0223678130284544
So, (byte)go != 0 can be used to check if any flags are set, and then Math.Log((byte)go, 2) % 1 == 0 to check if only one flag is set.
But, dasblinkenlight's solution seems like the best.
Off the top of my head:
var map = 1;
var count = 0;
while (map <= North_West)
{
if( ((int)Value & map) > 0)
count += 1;
map = map << 1; //left shift, a.k.a. multiply by 2
}
This is not a duplicate for counting the number of bits. If I initialize the enum like this and count the number of bits I get 10. But the number of set flags would be 8.
Please consider this statement directly from MSDN:
Flags enumerations are used for masking bit fields and doing bitwise comparisons.
If you are designing or using the enum in some manner that does NOT allow counting the number of flags using bitwise operations, then you are designing or using the enum improperly.
[Flags]
public enum MyEnum
{
Foo = 1,
Bar = 2,
Bizz = 4,
Buzz = 8,
Boo = 16
}
var foo = MyEnum.Foo | MyEnum.Foo | MyEnum.Bizz;
// foo == MyEnum.Foo | MyEnum.Bizz because setting the same flag twice does nothing
var bar = (MyEnum)27 // Some invalid combination
// bar == 27. Why would you do this instead of MyEnum.Boo | MyEnum.Buzz | MyEnum.Bar | MyEnum.Foo
If you design your enum properly, you can count the flag, and optionally short circuit if there is more than one flag set since continuing to count would be pointless.
var foo = MyEnum.Foo | MyEnum.Bizz;
int fooValue = (int)foo;
int numberOfFlags = 0;
while (fooValue > 0 && numberOfFlags < 2) // Stop counting if more than one flag since we don't need exact count
{
if ((fooValue & 1) == 1)
{
numberOfFlags++;
}
fooValue >>= 1;
}
Console.WriteLine(numberOfFlags);

NUnit setting Flag'd enum during TestCase

I'm trying to get Nunit's TestCase to work with a Flag'd Enum:
[NUnit.Framework.TestCase(Framework.Environments.HD3 | Framework.Environments.BizTalk, "Test","Test")]
public void SimpleTest(Framework.Environments environment, string org, string source)
{
environment = Framework.Environments.BizTalk| Framework.Environments.HI5;
....
The firstline in the test is to see if the value is set properly - it works.
The TestCase doesn't set the Enum though. It gets the HD3 and not the HIALUnSecured.
This is how my Enum is created:
[Flags]
public enum Environments
{
HD3 = 0,
HD1 = 1 << 0,
HD2 = 1 << 1,
HD4 = 1 << 2,
Any thoughts on how to get this to work? Yes I could use a 4th Variable, but I'm interested in finding out what's going on.
Update
On further investigation I found that Nunit might be the issue:
[TestCase("test", "test")]
public void test(string a, string b)
{
System.Diagnostics.Debug.Write("===============" + a + b);
}
Inside the method : a and b as null.
It's most likely something to do with my NUnit, i'll have to dig a bit.
Update 2
It seems TestDriven.NET was the culprit. It was not working as intended. I updated TestDriven and it worked perfectly.
You should modify your flags declaration, assuming HD3 is a flagable value.
public enum Environments
{
None = 0,
HD1 = 1 << 0, // 1
HD2 = 1 << 1, // 2
HD3 = 1 << 2, // 4
HD4 = 1 << 3, // 8
// etc.
}
In your first example, Framework.Environments.HD3 | Framework.Environments.BizTalk, assuming HD3 is zero, is equivalent to just writing Framework.Environments.BizTalk as anything OR'ed with zero is just the other operands value.
Here's a unit test to prove it works as I described.
[TestFixture]
class EnumFlagsTests
{
[Test]
[TestCase(Environments.HD1 | Environments.HD3)]
public void ShouldBeTrue(Environments input)
{
// arrange
Environments expectedEnum = (Environments.HD1 | Environments.HD3);
int expectedNumericalValue = 5;
// assert
Assert.AreEqual(expectedEnum, input);
Assert.AreEqual(expectedNumericalValue, (int)input);
}
}
[Flags]
public enum Environments
{
None = 0,
HD1 = 1 << 0, // 1
HD2 = 1 << 1, // 2
HD3 = 1 << 2, // 4
HD4 = 1 << 3, // 8
// etc.
}
NUnit definitely does not pass in null to test cases: if it did, NUnit's own tests would fail and we would have heard about it from folks!
I suspect that you may be using something other than NUnit's own runners to execute the tests. Is that the case?
TestDriven.NET was the culprit. Upgrading that worked.

Extending enum with Flags, interfere the current use

The system have a plain enum like this,
public enum SomeEnum : short
{
Ok = 0,
Missing = 17,
};
This enum are now into a situation where I need to mask some more information into it without change the appearence of the existing enum values. The enum will got some new values,
[Flags]
public enum SomeEnum : short
{
Ok = 0,
Missing = 17,
Blocking = 18, // Values could be anything
Low = 19, // Values could be anything
};
I was afraid there could be problem to the current enum usage. It appears that I'm right, but I hope i'm proved wrong with your help. The usage until today are built around SomeEnum.Ok. Also tomorrow, but the Ok need additional info. I need to mask the enum values without affect it's current behavior, which could came from any common reference;
someEnumVariable.ToString()
(int)someEnumVariable
someVar = SomeEnum.Ok
Enum.Parse(typeOf(SomeEnum), someString)
If I flag the enum with
var test = (SomeEnum.Ok | SomeEnum.Blocking);
Both flags can be founded i.e. test.HasFlags(SomeEnum.Ok) or test.HasFlags(SomeEnum.Blocking) but the enum represents as SomeEnum.Blocking, which aren't possible.
Any ideas?
Because the value of SomeEnum.OK is 0, calling HasFlag(SomeEnum.OK) will always return true. When you mask enums together, the process relies on the fact that the sum of any combination of enum values will be unique. Typically you would set these up starting using values of 2^0, 2^1, 2^2, etc. For example:
[Flags]
public enum SomeEnum : short
{
Ok = 1,
Missing = 2,
Blocking = 4, // Values could be anything
Low = 8, // Values could be anything
}
If you want to mask the values together, you'll have to use the Flags attribute. If you can't refactor and change the value of SomeEnum.OK, then you may have to rely on passing in a SomeEnum[], rather than a single masked SomeEnum value.
EDIT
Just a quick note on masking the values together using the enum defined above. Take the following code:
var t1 = (int)(SomeEnum.OK | SomeEnum.Missing); //t1 = 1 + 2 = 3
var t2 = (int)(SomeEnum.Missing | SomeEnum.Blocking); //t2 = 2 + 4 = 6
var t3 = (int)(SomeEnum.OK | SomeEnum.Low); //t3 = 1 + 8 = 9
var t4 = (int)SomeEnum.OK; //t4 = 1
var s1 = (SomeEnum.Ok).ToString(); //s1 = "Ok"
var s2 = (SomeEnum.Ok | SomeEnum.Missing).ToString(); //s2 = "Ok, Missing"
When these items are OR'ed together, .NET just adds the values together to produce a new, unique value that represents the combination of the OR'ed items. Using enum values that are powers of 2 ensures that the combinations will always be unique.
http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx
I think a quick introduction to binary OR is in order.
| doesn't just let you sneak two integers into one variable. It performs a mathematical operation.
Therefore, any value other than 0 OR'ed with 0 will return that value itself.
You will probably encounter further unexpected behavior if you supply flag values that are not a single bit, such as 1, 2, 4, 8, 16.
EDIT
If you want to build a Flags enum around the existing values, you can do that. Don't use the currently reserved bits 10001 (17) for any other value, and be careful when testing for Ok.
Here's an example of how to accomplish this using a bitflag. This will however likely force you to change your existing flag comparisons.
[FlagsAttribute]
enum tester
{
alpha = 1,
beta = 2,
gamma = 4,
reggy=3
}
class Program
{
static void Main(string[] args)
{
tester t = tester.alpha | tester.beta;
if (t == tester.alpha)
Console.WriteLine("alpha only");
if ((t & tester.alpha) != 0)
Console.WriteLine("alpha");
if ((t & tester.beta) != 0)
Console.WriteLine("beta");
if ((t & tester.gamma) != 0)
Console.WriteLine("gamma");
if (t == (tester.beta | tester.alpha))
Console.WriteLine("alphabeta");
//this will produce alpha, beta, alphabeta

C# Flag Charlie-Fox

I've been trying to emulate in C# a behavior which I was implementing without any problems in C++. I have a flag collection, which based on powers of 2, and a flag which I need to check if it exists in the collection.
byte flagCollection = 1 | 2 | 4 | 8;
byte flag = 2;
if ((flagCollection & flag) != 0) MessageBox.Show("y"); else MessageBox.Show("n");
Now, the problem is that whatever I set Flag to (2, 3, 100, 211), I always get "y", except for 0. Of course, 1, 2, 4, 8 would be some constants which have various meanings in my application.
In C++:
if (flagCollection & flag)
Would result in TRUE for the variables above.
The way you are doing it seems correct. I'm not really sure what behavior you are expecting. Any of the flags you listed (2, 3, 100, 211) do contain an element of 1 | 2 | 4 | 8. If you want to check whether all of them are present you should be doing
if ((flagCollection & flag) == flag)
// ...
well, if you're flag collection has OR'd 1,2,4,8, uh yes I think every positive integer that's not a multiple of 16 when &'d to it is going to return something. Or am I missing something?
Would this work?
[Flag]
public enum flagCollection {
Type1,
Type2,
Type4,
Type8,
}
flagCollection testValue = flagCollection.Type2
if ((testValue & flagCollection.Type2) == flagCollection.Type2) {
MessageBox.Show("y");
} else {
MessageBox.Show("n");
}
Not in front of the compiler so cant chek if that will work or not.

What does the [Flags] Enum Attribute mean in C#?

From time to time I see an enum like the following:
[Flags]
public enum Options
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option4 = 8
}
I don't understand what exactly the [Flags] attribute does.
Anyone have a good explanation or example they could post?
The [Flags] attribute should be used whenever the enumerable represents a collection of possible values, rather than a single value. Such collections are often used with bitwise operators, for example:
var allowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;
Note that the [Flags] attribute doesn't enable this by itself - all it does is allow a nice representation by the .ToString() method:
enum Suits { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
[Flags] enum SuitsFlags { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
...
var str1 = (Suits.Spades | Suits.Diamonds).ToString();
// "5"
var str2 = (SuitsFlags.Spades | SuitsFlags.Diamonds).ToString();
// "Spades, Diamonds"
It is also important to note that [Flags] does not automatically make the enum values powers of two. If you omit the numeric values, the enum will not work as one might expect in bitwise operations, because by default the values start with 0 and increment.
Incorrect declaration:
[Flags]
public enum MyColors
{
Yellow, // 0
Green, // 1
Red, // 2
Blue // 3
}
The values, if declared this way, will be Yellow = 0, Green = 1, Red = 2, Blue = 3. This will render it useless as flags.
Here's an example of a correct declaration:
[Flags]
public enum MyColors
{
Yellow = 1,
Green = 2,
Red = 4,
Blue = 8
}
To retrieve the distinct values in your property, one can do this:
if (myProperties.AllowedColors.HasFlag(MyColor.Yellow))
{
// Yellow is allowed...
}
or prior to .NET 4:
if((myProperties.AllowedColors & MyColor.Yellow) == MyColor.Yellow)
{
// Yellow is allowed...
}
if((myProperties.AllowedColors & MyColor.Green) == MyColor.Green)
{
// Green is allowed...
}
Under the covers
This works because you used powers of two in your enumeration. Under the covers, your enumeration values look like this in binary ones and zeros:
Yellow: 00000001
Green: 00000010
Red: 00000100
Blue: 00001000
Similarly, after you've set your property AllowedColors to Red, Green and Blue using the binary bitwise OR | operator, AllowedColors looks like this:
myProperties.AllowedColors: 00001110
So when you retrieve the value you are actually performing bitwise AND & on the values:
myProperties.AllowedColors: 00001110
MyColor.Green: 00000010
-----------------------
00000010 // Hey, this is the same as MyColor.Green!
The None = 0 value
And regarding the use of 0 in your enumeration, quoting from MSDN:
[Flags]
public enum MyColors
{
None = 0,
....
}
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.
You can find more info about the flags attribute and its usage at msdn and designing flags at msdn
You can also do this
[Flags]
public enum MyEnum
{
None = 0,
First = 1 << 0,
Second = 1 << 1,
Third = 1 << 2,
Fourth = 1 << 3
}
I find the bit-shifting easier than typing 4,8,16,32 and so on. It has no impact on your code because it's all done at compile time
Combining answers https://stackoverflow.com/a/8462/1037948 (declaration via bit-shifting) and https://stackoverflow.com/a/9117/1037948 (using combinations in declaration) you can bit-shift previous values rather than using numbers. Not necessarily recommending it, but just pointing out you can.
Rather than:
[Flags]
public enum Options : byte
{
None = 0,
One = 1 << 0, // 1
Two = 1 << 1, // 2
Three = 1 << 2, // 4
Four = 1 << 3, // 8
// combinations
OneAndTwo = One | Two,
OneTwoAndThree = One | Two | Three,
}
You can declare
[Flags]
public enum Options : byte
{
None = 0,
One = 1 << 0, // 1
// now that value 1 is available, start shifting from there
Two = One << 1, // 2
Three = Two << 1, // 4
Four = Three << 1, // 8
// same combinations
OneAndTwo = One | Two,
OneTwoAndThree = One | Two | Three,
}
Confirming with LinqPad:
foreach(var e in Enum.GetValues(typeof(Options))) {
string.Format("{0} = {1}", e.ToString(), (byte)e).Dump();
}
Results in:
None = 0
One = 1
Two = 2
OneAndTwo = 3
Three = 4
OneTwoAndThree = 7
Four = 8
In extension to the accepted answer, in C#7 the enum flags can be written using binary literals:
[Flags]
public enum MyColors
{
None = 0b0000,
Yellow = 0b0001,
Green = 0b0010,
Red = 0b0100,
Blue = 0b1000
}
I think this representation makes it clear how the flags work under the covers.
Please see the following for an example which shows the declaration and potential usage:
namespace Flags
{
class Program
{
[Flags]
public enum MyFlags : short
{
Foo = 0x1,
Bar = 0x2,
Baz = 0x4
}
static void Main(string[] args)
{
MyFlags fooBar = MyFlags.Foo | MyFlags.Bar;
if ((fooBar & MyFlags.Foo) == MyFlags.Foo)
{
Console.WriteLine("Item has Foo flag set");
}
}
}
}
I asked recently about something similar.
If you use flags you can add an extension method to enums to make checking the contained flags easier (see post for detail)
This allows you to do:
[Flags]
public enum PossibleOptions : byte
{
None = 0,
OptionOne = 1,
OptionTwo = 2,
OptionThree = 4,
OptionFour = 8,
//combinations can be in the enum too
OptionOneAndTwo = OptionOne | OptionTwo,
OptionOneTwoAndThree = OptionOne | OptionTwo | OptionThree,
...
}
Then you can do:
PossibleOptions opt = PossibleOptions.OptionOneTwoAndThree
if( opt.IsSet( PossibleOptions.OptionOne ) ) {
//optionOne is one of those set
}
I find this easier to read than the most ways of checking the included flags.
When working with flags I often declare additional None and All items. These are helpful to check whether all flags are set or no flag is set.
[Flags]
enum SuitsFlags {
None = 0,
Spades = 1 << 0,
Clubs = 1 << 1,
Diamonds = 1 << 2,
Hearts = 1 << 3,
All = ~(~0 << 4)
}
Usage:
Spades | Clubs | Diamonds | Hearts == All // true
Spades & Clubs == None // true
Update 2019-10:
Since C# 7.0 you can use binary literals, which are probably more intuitive to read:
[Flags]
enum SuitsFlags {
None = 0b0000,
Spades = 0b0001,
Clubs = 0b0010,
Diamonds = 0b0100,
Hearts = 0b1000,
All = 0b1111
}
#Nidonocu
To add another flag to an existing set of values, use the OR assignment operator.
Mode = Mode.Read;
//Add Mode.Write
Mode |= Mode.Write;
Assert.True(((Mode & Mode.Write) == Mode.Write)
&& ((Mode & Mode.Read) == Mode.Read)));
To add Mode.Write:
Mode = Mode | Mode.Write;
There's something overly verbose to me about the if ((x & y) == y)... construct, especially if x AND y are both compound sets of flags and you only want to know if there's any overlap.
In this case, all you really need to know is if there's a non-zero value[1] after you've bitmasked.
[1] See Jaime's comment. If we were authentically bitmasking, we'd
only need to check that the result was positive. But since enums
can be negative, even, strangely, when combined with the [Flags]
attribute,
it's defensive to code for != 0 rather than > 0.
Building off of #andnil's setup...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BitFlagPlay
{
class Program
{
[Flags]
public enum MyColor
{
Yellow = 0x01,
Green = 0x02,
Red = 0x04,
Blue = 0x08
}
static void Main(string[] args)
{
var myColor = MyColor.Yellow | MyColor.Blue;
var acceptableColors = MyColor.Yellow | MyColor.Red;
Console.WriteLine((myColor & MyColor.Blue) != 0); // True
Console.WriteLine((myColor & MyColor.Red) != 0); // False
Console.WriteLine((myColor & acceptableColors) != 0); // True
// ... though only Yellow is shared.
Console.WriteLine((myColor & MyColor.Green) != 0); // Wait a minute... ;^D
Console.Read();
}
}
}
Flags allow you to use bitmasking inside your enumeration. This allows you to combine enumeration values, while retaining which ones are specified.
[Flags]
public enum DashboardItemPresentationProperties : long
{
None = 0,
HideCollapse = 1,
HideDelete = 2,
HideEdit = 4,
HideOpenInNewWindow = 8,
HideResetSource = 16,
HideMenu = 32
}
Apologies if someone already noticed this scenario. A perfect example of flags we can see in reflection. Yes Binding Flags ENUM.
[System.Flags]
[System.Runtime.InteropServices.ComVisible(true)]
[System.Serializable]
public enum BindingFlags
Usage
// BindingFlags.InvokeMethod
// Call a static method.
Type t = typeof (TestClass);
Console.WriteLine();
Console.WriteLine("Invoking a static method.");
Console.WriteLine("-------------------------");
t.InvokeMember ("SayHello", BindingFlags.InvokeMethod | BindingFlags.Public |
BindingFlags.Static, null, null, new object [] {});
Define the Problem
Let’s define an enum that represents the types of users:
public enum UserType
{
Customer = 1,
Driver = 2,
Admin = 3,
}
We define the UserType enum that contains three values: Customer, Driver, and Admin.
But what if we need to represent a collection of values?
For example, at a delivery company, we know that both the Admin and the Driver are employees. So let’s add a new enumeration item Employee. Later on, we will show you how we can represent both the admin and the driver with it:
public enum UserType
{
Customer = 1,
Driver = 2,
Admin = 3,
Employee = 4
}
Define and Declare a Flags Attribute
A Flags is an attribute that allows us to represent an enum as a collection of values ​​rather than a single value. So, let’s see how we can implement the Flags attribute on enumeration:
[Flags]
public enum UserType
{
Customer = 1,
Driver = 2,
Admin = 4,
}
We add the Flags attribute and number the values with powers of 2. Without both, this won’t work.
Now going back to our previous problem, we can represent Employee using the | operator:
var employee = UserType.Driver | UserType.Admin;
Also, we can define it as a constant inside the enum to use it directly:
[Flags]
public enum UserType
{
Customer = 1,
Driver = 2,
Admin = 4,
Employee = Driver | Admin
}
Behind the Scenes
To understand the Flags attribute better, we must go back to the binary representation of the number. For example, we can represent 1 as binary 0b_0001 and 2 as 0b_0010:
[Flags]
public enum UserType
{
Customer = 0b_0001,
Driver = 0b_0010,
Admin = 0b_0100,
Employee = Driver | Admin, //0b_0110
}
We can see that each value is represented in an active bit. And this is where the idea of ​​numbering the values ​​with the power of 2 came from. We can also note that Employee contains two active bits, that is, it is a composite of two values Driver and Admin.
Operations on Flags Attribute
We can use the bitwise operators to work with Flags.
Initialize a Value
For the initialization, we should use the value 0 named None, which means the collection is empty:
[Flags]
public enum UserType
{
None = 0,
Customer = 1,
Driver = 2,
Admin = 4,
Employee = Driver | Admin
}
Now, we can define a variable:
var flags = UserType.None;
Add a Value
We can add value by using | operator:
flags |= UserType.Driver;
Now, the flags variable equals Driver.
Remove a Value
We can remove value by use &, ~ operators:
flags &= ~UserType.Driver;
Now, flagsvariable equals None.
We can check if the value exists by using & operator:
Console.WriteLine((flags & UserType.Driver) == UserType.Driver);
The result is False.
Also, we can do this by using the HasFlag method:
Console.WriteLine(flags.HasFlag(UserType.Driver));
Also, the result will be False.
As we can see, both ways, using the & operator and the HasFlag method, give the same result, but which one should we use? To find out, we will test the performance on several frameworks.
Measure the Performance
First, we will create a Console App, and in the .csproj file we will replace the TargetFramwork tag with the TargetFramworks tag:
<TargetFrameworks>net48;netcoreapp3.1;net6.0</TargetFrameworks>
We use the TargetFramworks tag to support multiple frameworks: .NET Framework 4.8, .Net Core 3.1, and .Net 6.0.
Secondly, let’s introduce the BenchmarkDotNet library to get the benchmark results:
[Benchmark]
public bool HasFlag()
{
var result = false;
for (int i = 0; i < 100000; i++)
{
result = UserType.Employee.HasFlag(UserType.Driver);
}
return result;
}
[Benchmark]
public bool BitOperator()
{
var result = false;
for (int i = 0; i < 100000; i++)
{
result = (UserType.Employee & UserType.Driver) == UserType.Driver;
}
return result;
}
We add [SimpleJob(RuntimeMoniker.Net48)], [SimpleJob(RuntimeMoniker.NetCoreApp31)], and [SimpleJob(RuntimeMoniker.Net60)] attributes to the HasFlagBenchmarker class to see the performance differences between different versions of .NET Framework / .NET Core:
Method
Job
Runtime
Mean
Error
StdDev
Median
HasFlag
.NET 6.0
.NET 6.0
37.79 us
3.781 us
11.15 us
30.30 us
BitOperator
.NET 6.0
.NET 6.0
38.17 us
3.853 us
11.36 us
30.38 us
HasFlag
.NET Core 3.1
.NET Core 3.1
38.31 us
3.939 us
11.61 us
30.37 us
BitOperator
.NET Core 3.1
.NET Core 3.1
38.07 us
3.819 us
11.26 us
30.33 us
HasFlag
.NET Framework 4.8
.NET Framework 4.8
2,893.10 us
342.563 us
1,010.06 us
2,318.93 us
BitOperator
.NET Framework 4.8
.NET Framework 4.8
38.04 us
3.920 us
11.56 us
30.17 us
So, in .NET Framework 4.8 a HasFlag method was much slower than the BitOperator. But, the performance improves in .Net Core 3.1 and .Net 6.0. So in newer versions, we can use both ways.
Flags are used when an enumerable value represents a collection of
enum members.
here we use bitwise operators, | and &
Example
[Flags]
public enum Sides { Left=0, Right=1, Top=2, Bottom=3 }
Sides leftRight = Sides.Left | Sides.Right;
Console.WriteLine (leftRight);//Left, Right
string stringValue = leftRight.ToString();
Console.WriteLine (stringValue);//Left, Right
Sides s = Sides.Left;
s |= Sides.Right;
Console.WriteLine (s);//Left, Right
s ^= Sides.Right; // Toggles Sides.Right
Console.WriteLine (s); //Left

Categories