views:

220

answers:

4

Hi,

My object Item has several binary states which can be combined

bool CanBeSold;
bool CanBeBought;
bool CanBeExchanged;

I need to store current combination of values into one variable. The reason is that I need to store this value in DB. In C++ I would create a bit-mask where one state occupies some bit. Is it good practice in .NET?

+14  A: 

You can use an enumeration with the Flags attribute:

[Flags]
enum MyStates {
  CanBeSold = 1,
  CanBeBought = 2,
  CanBeExchanged = 4
}

Since enumerations are integral data types underneath you can combine them in the usual fashion:

state = MyStates.CanBeSold | MyStates.CanBeExchanged

Note that this only works when the enum values are powers of two (as Doug Ferguson pointed out in a comment), so they can be combined easily and don't overlap when multiple ones are set.

You can also define values as combinations of multiple other values:

 CanBeSoldOrBought = CanBeSold | CanBeBought

or

 CanBeSoldOrBought = 3

which then also works as expected. This can be seen for example for file permissions where ReadWrite usually is a combination of the Read and Write bits.

And yes, that's quite a common practice. The framework itself also uses it in several places.

The usual way to check for a particular bit being set is then

if ((state & MyStates.CanBeSold) != 0) { ... }
Joey
Thanks, but what is [Flags] attribute for? The only purpose I can expect to avoid type-safety error. Am I right?
Captain Comic
@Captain Comic: It's to indicate that it's reasonable to combine the values. It also changes the parsing and formatting behaviour.
Jon Skeet
I there a list somewhere where one can read up on all these nifty 'attributes'? And can one define these things themselves too?
Toad
reinier: You can create them yourself: http://msdn.microsoft.com/en-us/library/sw480ze8.aspx
Joey
The enum values should be powers of 2 (as shown in the answer) so that they do not overlap.
Doug Ferguson
Thanks Doug, I made that a little clearer now :)
Joey
johannes: thanks for the pointer
Toad
+2  A: 

You can do this with bit masks in .NET too.

Within your enum you can define your states as values

public enum ItemState { CanBeSold = 1; CanBeBought = 2; CanBeExchanged = 4 }

Then within your object, you can do

if (item.State ^ ItemState.CanBeSold) ....
Tim
I don't understand your example code. The ^ (logical Xor operator) is typically not used directly in an if statement (At least I never see it used as such). Can you explain what the If statement achieves? I wonder if one can even compile it since it won't even return a boolean
Toad
+2  A: 

You can use a Flags enum with each bit specified

[Flags]
enum MyStates {
    CanBeSold = 0x1,
    CanBeBought = 0x2,
    CanBeExchanged = 0x4,
}

MyStates m_Flags;

// to set a flag:
m_Flags |= MyStates.CanBeSold;

// to unset a flag:
m_Flags &= ~MyStates.CanBeSold;
thecoop
+5  A: 

Create an enum where the values correspond to bits in an integer. Adding the Flags attribute enabled you to do some more bit operations on the enum values.

[Flags]
public enum CanBe {
  Sold = 1,
  Bought = 2,
  Exchanged = 4
}

Now you can just use the or operator between the values:

CanBe can = CabBe.Sold | CanBe.Exchanged.

You can add a state with the |= operator:

can |= CanBe.Sold;

Or several states:

can |= CanBe.Sold | CanBe.Bought;

You can keep a state with the &= operator:

can &= CanBe.Sold;

Or several states:

can &= CanBe.Sold | CanBe.Bought;

You can remove states by using the ~ operator to create a complement to a value:

can &= ~CabBe.Bough;

Or seveal states:

can &= ~(CabBe.Bough | CanBe.Exchanged);

You can check for a state using the & operator:

if ((can & CanBe.Sold) != 0) ...

Or several states at once:

if ((can & (CanBe.Sold | CanBe.Bought)) != 0) ...

Or check that several states are all set:

if ((can & (CanBe.Sold | CanBe.Bought)) == (CanBe.Sold | CanBe.Bought)) ...
Guffa