Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A helpful way to use the FlagsAttribute with enumerations

0.00/5 (No votes)
10 Sep 2008 1  
Bitwise operations with enumerations.

Introduction

I was assigned the task of creating an application that consumes a couple of RSS feeds to compile a concise list of recent news headlines from various sources and various categories, including top news headlines, sports, business, entertainment, politics, etc.

The final top level class is a ContentMonitor that downloads new content at every specified interval. When an instance of a ContentMonitor object is created, I wanted the user's of the class to be able to specify which feeds it should monitor and from which a master list of headlines should be compiled and exported to a local XML document.

After thinking a bit about it, I decided to create a NewsCategory enumeration that implements the FlagsAttribute so that the user of the class could pass any combination of news categories to the ContentMonitor, which would then be responsible for retrieving those specified headlines.

The implementation of the monitor class isn't relative to this article, but I wanted to show how I went about using bitwise operations to pass a "list" of enum values into an object, and then to retrieve those values on the other side to determine which headlines were being requested.

Background

If you need to familiarize yourself with bitwise operations, check out this article. The official MSDN documentation on the FlagsAttibute class can be found here. I won't go into any specific detail about how bitwise operations work. I assume that if you're reading this, you already know a thing or two.

Using the code

Enough chit chat. On to the code.

Here is the declaration of my NewsCategory enumeration:

[FlagsAttribute]
public enum NewsCategory : int 
{
    TopHeadlines =1,
    Sports=2,
    Business=4,
    Financial=8,
    World=16,
    Entertainment=32,
    Technical=64,
    Politics=128,
    Health=256,
    National=512
}

And, here is the property of the ContentMonitor that sets the NewsCategory member:

public NewsCategory ContentCategories
{
    set
    {
        int[] arr = (int[])System.Enum.GetValues(typeof(NewsCategory));
        int largest = GetLargestValue(arr); //value of largest enum constant
        int smallest = GetSmallestValue(arr); //value of smallest enum constant

        for (int i = smallest; i <= largest; i = i * 2) // i * 2 because of bitwise flags
        {
            switch ((NewsCategory)(value & (NewsCategory)i))
            {
                case NewsCategory.Business: break;
                case NewsCategory.Entertainment: break;
                case NewsCategory.Financial: break;
                case NewsCategory.Health: break;
                case NewsCategory.National: break;
                case NewsCategory.Politics: break;
                case NewsCategory.Sports: break;
                case NewsCategory.Technical: break;
                case NewsCategory.TopHeadlines: break;
                case NewsCategory.World: break;
                default: break;
            }
        }
    }
}

And finally, here is how the ContentMonitor is "told" which news content to consume using a bitwise OR operation.

ContentMonitor mon = new ContentMonitor();

// Tell the monitor which news headlines we want
mon.ContentCategories = NewsCategory.Business | 
                        NewsCategory.Entertainment | 
                        NewsCategory.Politics;

So, let's break this apart.

The very first thing I wanted to do was retrieve the smallest and largest constant values of the NewsCategory enumeration. Assume that the methods GetLargestValue() and GetSmallestValue() return the largest and smallest numbers in the array that's passed to the them, respectively.

Now, I set up a for loop to iterate from the smallest enum value to the largest, in multiples of two. If the smallest enum constant were 1, and the largest were 512, at each iteration of the loop, i would be 1, 2, 4, 8, 16, 32, 64, etc., all the way to 512. Note that by getting the smallest and largest constants dynamically, I don't have any numbers hard-coded in the for loop. If I decided to add a new item to my enumeration and assign it the value of 1024 (512 * 2), I only have to update the enumeration declaration itself. This, way the loop still knows how many iterations to go through to cover all the enum values.

Now that we've passed a "list" of bitwise NewCategory values to the ContentMonitor, how do we know what ones we've got to deal with? This is where bitwise AND comes into play. One way of retrieving the values would be like this:

if ((value & NewsCategory.Politics) == NewsCategory.Politics) {...}
if ((value & NewsCategory.Business) == NewsCategory.Business) {...}
if ((value & NewsCategory.Financial) == NewsCategory.Financial) {...}

Mostly for readability, I didn't want to do a bunch of bitwise AND operations placed in a series of if statements where I had to type the NewsCategory twice in the same line. I always love it when I can make concise, easy to read modules of code. (Yes, I could have put the AND operation in a function, and just passed in the news category that way, but I didn't like that either.)

If you look at the switch statement, it's doing basically the same thing as the series of if statements above. It takes the current value of i (which represents an enum constant value) and typecasts it to a NewsCategory enum. Simple enough. After that, it uses the NewsCategory value passed into the property, and performs a bitwise AND operation on it, which results in a NewsCategory value that can be used in a switch statement. It's basically like doing the following:

value = NewsCategory.Business | NewsCategory.Entertainment;
   
NewsCategory tmpCat = (NewsCategory)4; // Returns NewsCategory.Business
NewsCategory newCat = (value & tmpCat);
if (newCat == NewsCategory.Business)
{
     // We've got business
}

Now, just test your conditions in the body of the switch. I may have spent way more time creating this and writing about it than was really necessary, but it helped me understand more about how to use bitwise operations to pass multiple values into a class, and extract them to perform specific actions for each value. Hopefully, this will work for you sometime along the way. Also, if you feel anything in this article is erroneous or false, please don't hesitate to tell me. I love feedback and learning new things.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here