Click here to Skip to main content
Click here to Skip to main content

A helpful way to use the FlagsAttribute with enumerations

, 10 Sep 2008
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

remarkpk11
Software Developer (Junior) IT IS AG
United States United States
No Biography provided

Comments and Discussions

 
GeneralCorrection Pinmemberremarkpk1110-Sep-08 16:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140823.1 | Last Updated 10 Sep 2008
Article Copyright 2008 by remarkpk11
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid