Long overdue Enum goodness in .NET 4

The more I investigate the changes in Version 4 of the .NET framework, the more I find little tweaks that just reduce the pain of day to day programming.  For example, the System.Enum class is getting some extra methods that finally make day to day programming a bit simpler.

The first important addition to System.Enum is the addition of Enum.TryParse<T>.  This has some great advantages over the .NET 3.5 and earlier parsing of enum values, including the ability to have error checking without throwing exceptions and to have type safety which avoids boxing and casting.

This just is nice – even the MSDN samples just look more clean and elegant.  Consider the original Enum.Parse sample:

try
{
    Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString, true);
}
catch (ArgumentException e)
{
    // Handle errors
}

In order for this to work correctly, we need to wrap the entire thing in a try/catch block to handle the potential exception, we have to cast our results from System.Object back to “Colors”, and we have to specify the type explicitly (typeof(Colors)) in the call.  Not very friendly.

In .NET 4, we can simplify this dramatically:

Colors colorValue;
if (!Enum.TryParse(colorString, true, out colorValue))
{
    // Handle error
}

Not only is this safer (you’re now getting compile-time checking that it’s the correct type of Enum), you don’t have to use exception handling for a simple case like this.  In addition, you’re avoiding boxing the result into an object and casting it back (unboxing it) to a Colors type.  Very nice addition!

The second addition to Enum is just as exciting – Enum.HasFlag.  Dealing with flag enum values has always been problematic, and a source of confusion for many people.  In .NET 3.5, if you want to check for the existence of a flag, it was odd to say the least.  For example, say we have the following flags enum:

[Flags]
enum TestFlags
{
    One = 1,
    Two = 2,
    Four = 4,
    Eight = 8,
    Sixteen = 16
}

In .NET 3.5, to check for the existence of a flag, you had to write:

bool hasOneFlag = (variable & TestFlags.One) == TestFlags.One;

Definitely not short to type, and quite confusing for many beginning programmers.  Many people (including myself) have tried to create extension methods to ease this, the best probably being Jon Skeet’s Unconstrained Melody, which adds a HasAny() extension method for enum.  However, this approach required IL rewriting, and was impossible to accomplish in C# directly.

Version 4 of the .NET Framework finally addresses this very common scenario with the addition of Enum.HasFlag.  This lets us simplify the above line to:

bool hasOneFlag = variable.HasFlag(TestFlags.One);

This is much easier to understand, less confusing to type, and very nice overall.

Here’s a short program demonstrating both of these new methods:

[Flags]
enum TestFlags
{
    One = 1,
    Two = 2,
    Four = 4,
    Eight = 8,
    Sixteen = 16
}

class Program
{
    static void Main(string[] args)
    {
        TestFlags variable;
        Enum.TryParse("Eight, sixteen", true, out variable);
        Console.WriteLine(variable);
        Console.WriteLine(variable.HasFlag(TestFlags.Two));
        Console.WriteLine(variable.HasFlag(TestFlags.Eight));
        Console.WriteLine(variable.HasFlag(TestFlags.Sixteen));

        Console.ReadKey();
    }
}

When run, this outputs:

Eight, Sixteen
False
True
True

Very nice additions!

About Reed
Reed Copsey, Jr. - http://www.reedcopsey.com - http://twitter.com/ReedCopsey

Comments

12 Responses to “Long overdue Enum goodness in .NET 4”
  1. Very nice feature, indeed and definitely overdue. I always wondered why flags weren’t treated slightly different than regular enums and maybe provide a context keywords such as “in” (has is better though) and flagged for the definition (instead of the attribute). I don’t know, something to hide the bitwise operations that aren’t really more than implementation details.

    Something like this:

    public flagged enum Days
    {
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
    }

    Days meetingDays = Days.Monday and Days.Tuesday and Days.Thursday;

    if (Days.Friday in meetingDays)
    {
    }

    Of course, I’m sure there’s an excellent reason as to why this wasn’t done like this… never really tried to figure it out.

    Still, I wasn’t aware of this new feature. Thanks for the heads up!

    Fernando

  2. Reed says:

    Interesting idea. I’d guess it has to do with being consistent with how flags are handled in the Windows API and other technologies/languages. It would be odd to all of a sudden be using “and” when everything always used “or” previously (even if it is nicer syntax). I do like the idea of language support for flags instead of using attributes, very much.

  3. Dan Atkinson says:

    Or you could just write your own extension…

    public class Enum
    {
    public static T Parse(string value)
    {
    return (T)Enum.Parse(typeof(T), value, true);
    }
    }

    Usage:
    Enum.Parse(colorString);

    Now, I don’t know about you, but I think mine is so much cleaner! If you really want, you can handle the try/catch in there, but if you’re concerned about it failing, then you should consider using a concrete class instead.

  4. Dan Atkinson says:

    It has <T> on the class, but you can see that.

  5. Reed says:

    Dan,

    It’s still a bit odd, usage wise, though – There’s no way to infer T, so you have to write:

    Colors color = Enum
    .Parse(colorString);

    Also, TryParse is nice because it will not throw if there’s an error, which is a very useful feature.

  6. JD says:

    HasFlag looks nice. I’m trying to see if it will also have methods for flipping on/off a flag? For example, SetFlag and UnsetFlag…doesn’t look like it from glancing at MS docs. Would have been useful for easy way to unset a particular flag as this post here indicates you need to OR, then XOR to unset a particular flag – http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/3358c90e-39bd-4516-8207-cafb54877354

  7. JD says:

    Also, found this reference here: http://stackoverflow.com/questions/93744/most-common-c-bitwise-operations/417217#417217

    Would be nice to have: HasFlag, AddFlag, RemoveFlag

  8. Reed says:

    JD:

    You can add to a flag enum using |=, which is very easy and concise:

    variable |= TestFlags.Sixteen;

    This will add the Sixteen flag to variable.

    Unfortunately, removing a flag isn’t quite as easy. If you know, for sure, that the flag is set, you can do:

    variable ^= TestFlags.Sixteen;

    However, if the flag is not set, the above will add it (it flips the flag bit, not removes it).

    There is no AddFlag/RemoveFlag in .NET 4, though.

  9. Moby Disk says:

    Enum is still missing the most obvious one:

    public static TEnum Parse(string value, bool ignoreCase);

    It can’t infer the enum type since it is a return value, but it still beats passing typeof(T). Oh well.

  10. Quagmandir says:

    Sorry for the necromancy but, I found you whilst looking for Enum goodies.

    Now, as I have only today found this out myself, I felt I had to point out that the following statement is inaccurate:

    “Unfortunately, removing a flag isn’t quite as easy.”

    I believe you can use:

    variable &= ~TestFlags.Sixteen;

    The ( ~ ) operator, apparently, AND’s the _negative_ of the given flag.

    Thanks, and enjoy!

  11. Candide says:

    enum.HasFlags is about a hundred times slower than testing the bit direcly.

    • Reed says:

      Candide – It is slower, but that’s often not an issue. If you’re doing this in a tight loop where perf. matters, then yes, you might want to avoid this call. I do like the additional clarity involved in the method call, in most cases.

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!