Thursday, March 20, 2008

Multiple Boolean Variables Without all The Declarations

I need to have a bunch of boolean variables. Say I have a Car class that needs to indicate a bunch of features like air conditioning, leather seats, stereo, power windows, power seats or alarm system. I could declare the Car class like this:


public Car
{
public string Make;
public string Model;
public bool AirConditioning;
public bool LeatherSeats;
public bool Stereo;
public bool PowerWindows;
public bool PowerSeats;
public bool AlarmSystem;


Instead of declaring each variable individually you could use an enumeration flag. An enumeration flag uses bit wise operations on integer variables to represent multiple boolean variables. If you want to know more about bit wise operators take a look at the bit wise operation Wikipedia article.

Going back to our Car class we could declare the enumeration flag:


[Flags]
enum CarFeatures
{
AirConditioning=1,
LeatherSeats=2,
Stereo=4,
PowerWindows=8,
PowerSeats=16,
AlarmSystem=32
}


Remember each value needs to be a power of 2, because we are using them as bits and not as an integer. If you wanted more values then we have here you would continue with 64, 128, 256, 512, 1024, 2048, etc... Now we can declare our Car class's features as one variable:


public class Car
{
public string Make;
public string Model;
public CarFeatures Features;
}


To initialize our Car's features we can assign it as we would any other enumerator:


Car myCar = new Car();
myCar.Features = CarFeatures.Stereo;


If we want to assign it more then one value we need to use the or ("|") bit wise operator. It might help to think of the bit wise or ("|") as a merge or combine operator. Here is what it would look like in our Car example;


Car myCar = new Car();
myCar.Features = CarFeatures.Stereo | CarFeatures.AirConditioning;


Now that we have our features assigned to the Car how do we use them? Lets say we are looking for Cars that have air conditioning. Couldn't we use a standard comparison test? Example:


if (myCar.Features == CarFeatures.AirConditioning)
{
// This car has Air Conditioning
}


You would find cars with air conditioning, but the cars you would find wouldn't have any other features, including our previous car that had a stereo and air conditioning. In order to find cars that have air conditioning regardless of the other features we need to use the bit wise and ("&") operator. Lets rewrite our previous example to use the bit wise and ("&") operator:


if (myCar.Features & CarFeatures.AirConditioning == Car.Features.AirConditioning)
{
// This car has air conditioning and possibly other features as well.
}


The bit wise and ("&") operator extracts the CarFeatures.AirConditioning bit from myCar.Features. We need to the equals operator to actually test the bit we extracted. If the bit is "off" we will get 0. If the bit is "on" we will get the value of the bit in the CarFeatures.AirConditioning bit this would be 1. Here is a diagram of what is ocurring:


000101 (myCar.Features)
& 000001 (CarFeatures.AitConditioning)
--------
000001

000001 == 000001? True


Now you understand what going on. What about the length of the comparison? Well you can shorten it like this:


if (myCar.Features & Features.AirConditioning != 0)
{
// This car has air conditioning.
}


Both statements are correct. Just use them consistently.

Flag enumerations are great, but you should not go and replace all of your boolean values with enumeration flags. There are times when they can come in handy, but use them wisely.

Save to del.icio.us Add to Technorati Add to dzone

No comments: