Snippet: Multi-Valued Enums - Extension Method Style

Omar blogged a method to extract the selected values in an enumeration:

http://blog.omarbesiso.net/index.php/2008/02/13/c-multi-valued-enumerators-flags/

Suppose you had an flags enumeration called Option. You could use his method to write the following code:

Options options = Options.ReadOnly | Options.Archive;
Console.WriteLine("You selected:");
foreach (Options option in EnumHelper.GetSelectedEnumValues<Options>(options))
{
    Console.WriteLine(option);
}

While a generic static method is fine, I think this is a good example of where an extension method would make for a more readable solution. Using his method could look like this:

Options options = Options.ReadOnly | Options.Archive;
Console.WriteLine("You selected:");
foreach (Options option in options.Selected())
{
    Console.WriteLine(option);
}

Achieving this is very simple. The bold parts were the only changes I made in order to convert the method into an extension method:

    static class EnumExtensions
    {
        public static Collection<T> Selected<T>(this T enumInputValue)
            where T : struct
        {
            Type enumType = typeof(T);
            if (!enumType.IsEnum)
            {
                throw new ArgumentException(enumType.ToString()
                    + " is not an Enum.", "T", null);
            }

            Array enumValues = Enum.GetValues(enumType);
            long inputValueLong = Convert.ToInt64(enumInputValue);
            Collection<T> enumOutputCollection = new Collection<T>();

            foreach (T enumValue in enumValues)
            {
                long enumValueLong = Convert.ToInt64(enumValue);

                if ((enumValueLong & inputValueLong) == enumValueLong
                    && enumValueLong != 0)
                {
                    enumOutputCollection.Add(enumValue);
                }
            }

            if (enumOutputCollection.Count == 0 && enumValues.GetLength(0) > 1)
            {
                T enumNoneValue = (T)enumValues.GetValue(0);
                if (Convert.ToInt64(enumNoneValue) == 0)
                {
                    enumOutputCollection.Add(enumNoneValue);
                }
            }

            return enumOutputCollection;
        }
    }

You could go a step further by "yield return’ing" the items and returning an IEnumerable<T> rather than a Collection<T>, but I don’t expect it would make any difference in reality. Changing the return value to an IEnumerable<T> rather than a Collection<T> is probably a nicer design though.

Sure, extension methods can be abused, but I think this is another case where they makes the intent of the code clearer. That said, I have plenty of examples where I’ve taken them too far :)

5 Responses to “Snippet: Multi-Valued Enums - Extension Method Style”

  1. I’d love to see some of the examples of how not to use extension methods :-)

  2. I’m not sure if I’d use “Selected()”, but this made me think of an enum extension method that would be handy:

    public static bool Contains(this T enumValue)
    {

    }

    So if I had a multivalued enum I could simply say:

    if (myEnumValue.Contains(MyEnum.OnePossibleValue)) { … }

    Much nicer than the “bitwise &” syntax.

  3. Noice. :)

    Good to see alternatives to the type safe enum pattern for encapsulation too.

  4. This just makes me cringe.. whatever happened to using the bitwise operations that are instant? A few dozen machine instructions are now turned into hundreds of complicated function calls.

  5. @John Smith,

    Yep, if I found myself doing comparrisons over a billion enums in a scallable system, I might reconsider this method. Otherwise, I tend to favour readability.

    Intel still haven’t refunded me for last year’s Unused CPU Cycles declaration.

    Paul

Leave a Reply