For instance :
Say you want to define the nature of a person.
public enum Character { Caring, Honest, Loving, Desparate, Obedient, Logical, Practical }You might name these characteristics using numeric values, say you have Honest as 1, Loving as 2 etc. But it would be more logical to use an Enum instead.
Hmm... Putting it further, Enum might also come very handy when you want to use a combination of the same. Say for instance, a person can be both Logical and Caring. Now how could you define this? Do you need to define enumeration values for each of them ? I guess that would not be a good choice either.
Flags attribute in Enum plays a vital role if you want to use the values of an enumeration in combinations. So that each combination of enumeration values are mutually exclusive and does not overlap with another value of Enum. For bit fields, it is very easy and yet very handy to use Flags attribute rather than using your own logic to define the flags yourself.
Steps to create BitField Enumeration :
- Define each enumeration and set the value of each enumeration to be a power of 2.
- Put a Flags attribute for the enumeration.
[Flags] public enum Character : int { Caring =0, Honest=1, Loving=2, Desparate=4, Obedient=8, Logical=16, Practical=32 }Hence the only thing that you need to do to declare a BitField in .Net is to declare the values of enumeration as a multiple of 2 and apply a Flags attribute to the type.
Hence the Character enumeration can now act in Bitwise Operators. The values of the Enumeration will look like
00000000 0 00000001 1 00000010 2 00000100 4 00001000 16 00010000 32 00100000 64 01000000 128
Add Flag Combinations :
To add more than one flag you could use | operator or bitwise OR operator. Say for instance you want to define a character which is both Caring, Logical and Practical. In such a case you could easily declare
Character mycharacter = Character.Caring | Character.Logical | Character.Practical;Here the mycharacter variable will combine each of the values of Caring, Logical and Practical using bitwise OR operator.
Checking Flag Contains :
& Operator in Bitfield can be used to check whether the BitField contains the Flag. Say for instance :
Character mycharacter = Character.Caring | Character.Logical | Character.Practical; if ((mycharacter & Character.Caring) == Character.Caring) Console.WriteLine("The man is caring");
Here the bitwise operator & allows you to compare if mycharacter has certain flag in it.
Note :
In case of dealing with Bit Flags, it is always a good idea to avoid using 0 as a valid value for the Enum. In our case, say I use Character.Caring as my first value. Now,
Character newchar = new Character()
Console.WriteLine(newchar.HasFlag(Characters.Caring));
Returns true, as 0 is the initial value for any Enumeration.
Another thing that you should remember,
newchar & Character.Caring = Character.Caring
Thus you cannot separate the value Character.Caring from the enumeration. So it would be better to use None as 0 for Flags enumeration.
# I would like to thank jmeyer43 for pointing out this to me.
For further reading
To read more about Flags attribute usage you can go to MSDN link and read the Usage Guidelines.
Thank you, I hope you find interests while reading the post.
Instead of:
ReplyDelete(mycharacter & Character.Caring) == Character.Caring
Better:
mycharacter.HasFlag(Character.Caring)
(only in .NET 4.0)
Good call @annonymous.
ReplyDeleteCheers.
An habit I have for this kind of enumeration is to use hexadecimal values. This way, for bigger values, you have an easier sequence of numbers to use :
ReplyDelete&H0
&H1
&H2
&H4
&H8
&H10
&H20
&H40
&H80
&H100
&H200
&H400
&H800
&H1000
etc ...
Remember that in a flags enum, 0 is none. Every value that's not None needs a bit to turn on and off, in the example Caring doesn't have a bit.
ReplyDeleteOh yes.. I think it is always better to avoid 0 as starting index.
ReplyDeleteTwo reasons for that :
1. Default value is 0
2. You cannot determine if the it is there in the combination.
Characters cc = Characters.Desparate | Characters.Loving | Characters.Obedient;
Console.WriteLine(cc.HasFlag(Characters.Caring));
will return true.
Good to see the comment. Will add it to the post shortly.
Good article, but i cudnt get the NOTE part you have explained.
ReplyDeleteThanks.
@Zen
ReplyDeleteActually for Enums which you want to use as BitField, I said it is better to avoid first position 0 for a value rather start from 1 and leave 0 for None.
If you see the comment just above your one, you can get what I am pointing to.
Thanks.
ReplyDeleteSo to have the Enum work like BitField, is it necessary to have the value for item being set as power of 2?
Whats the internal funda here?
Thanks
@Zenwalker
ReplyDeleteThe internal funda is you can generate all combination of values from your Enum
Means 0th|1st|2nd will give you 3
where 4th is 2 to power 2 which is 4. So the values doesnt overlap.
I had to specify the working days in a week for a company in my website. Bit flag enumeration helped me do so. I had implemented it long back but the article helped me brush up few missing points.
ReplyDeleteYou could also use:
ReplyDeleteCaring = 1 << 0
Honest = 1 << 1