by James Michael Hare
on Geeks with Blogs
See other posts from Geeks with Blogs
or by James Michael Hare
Published on Thu, 09 Dec 2010 23:50:43 GMT Indexed on 2010/12/10 22:19 UTC
Read the original article Hit count: 344
Once again lets dive into the Little Wonders of .NET, those small things in the .NET languages and BCL classes that make development easier by increasing readability, maintainability, and/or performance.
So probably every one of us has used an enumerated type at one time or another in a C# program. The enumerated types we create are a great way to represent that a value can be one of a set of discrete values (or a combination of those values in the case of bit flags).
But the power of enum types go far beyond simple assignment and comparison, there are many methods in the Enum class (that all enum types “inherit” from) that can give you even more power when dealing with them.
IsDefined() – check if a given value exists in the enum
Are you reading a value for an enum from a data source, but are unsure if it is actually a valid value or not? Casting won’t tell you this, and Parse() isn’t guaranteed to balk either if you give it an int or a combination of flags. So what can we do?
Let’s assume we have a small enum like this for result codes we want to return back from our business logic layer:
In this enum, Success will be zero (unless given another value explicitly), Warning will be one, and Error will be two.
So what happens if we have code like this where perhaps we’re getting the result code from another data source (could be database, could be web service, etc)?
So what happens if result is –1 or 4? Well, the cast does not fail, so what we end up with would be an instance of a ResultCode that would have a value that’s outside of the bounds of the enum constants we defined.
This means if you had a block of code like:
That you would hit none of these blocks (which is a good argument for always having a default in a switch by the way).
So what can you do? Well, there is a handy static method called IsDefined() on the Enum class which will tell you if an enum value is defined.
In fact, this is often recommended after you Parse() or cast a value to an enum as there are ways for values to get past these methods that may not be defined.
If you don’t like the syntax of passing in the type of the enum, you could clean it up a bit by creating an extension method instead that would allow you to call IsDefined() off any isntance of the enum:
HasFlag() – an easier way to see if a bit (or bits) are set
Most of us who came from the land of C programming have had to deal extensively with bit flags many times in our lives. As such, using bit flags may be almost second nature (for a quick refresher on bit flags in enum types see one of my old posts here).
However, in higher-level languages like C#, the need to manipulate individual bit flags is somewhat diminished, and the code to check for bit flag enum values may be obvious to an advanced developer but cryptic to a novice developer.
For example, let’s say you have an enum for a messaging platform that contains bit flags:
We can combine these bit flags using the bitwise OR operator (the ‘|’ pipe character):
Now, if we wanted to check the flags, we’d have to test then using the bit-wise AND operator (the ‘&’ character):
While the ‘|’ for combining flags is easy enough to read for advanced developers, the ‘&’ test tends to be easy for novice developers to get wrong. First of all you have to AND the flag combination with the value, and then typically you should test against the flag combination itself (and not just for a non-zero)!
This is because the flag combination you are testing with may combine multiple bits, in which case if only one bit is set, the result will be non-zero but not necessarily all desired bits!
Thanks goodness in .NET 4.0 they gave us the HasFlag() method. This method can be called from an enum instance to test to see if a flag is set, and best of all you can avoid writing the bit wise logic yourself. Not to mention it will be more readable to a novice developer as well:
It is much more concise and unambiguous, thus increasing your maintainability and readability.
It would be nice to have a corresponding SetFlag() method, but unfortunately generic types don’t allow you to specialize on Enum, which makes it a bit more difficult. It can be done but you have to do some conversions to numeric and then back to the enum which makes it less of a payoff than having the HasFlag() method.
But if you want to create it for symmetry, it would look something like this:
Note that since the enum types are value types, we need to assign the result to something (much like string.Trim()). Also, you could chain several SetFlag() operations together or create one that takes a variable arg list if desired.
Parse() and ToString() – transitioning from string to enum and back
Sometimes, you may want to be able to parse an enum from a string or convert it to a string - Enum has methods built in to let you do this. Now, many may already know this, but may not appreciate how much power are in these two methods.
For example, if you want to parse a string as an enum, it’s easy and works just like you’d expect from the numeric types:
Note that Enum.Parse() will throw if it finds a value it doesn’t like. But the values it likes are fairly flexible! You can pass in a single value, or a comma separated list of values for flags and it will parse them all and set all bits:
Or you can parse in a string containing a number that represents a single value or combination of values to set:
And, if you really aren’t sure if the parse will work, and don’t want to handle an exception, you can use TryParse() instead:
So we covered parsing a string to an enum, what about reversing that and converting an enum to a string? The ToString() method is the obvious and most basic choice for most of us, but did you know you can pass a format string for enum types that dictate how they are written as a string?:
Now, you may not really see a difference here between G and F because I used a [Flags] enum, the difference is that the “F” option treats the enum as if it were flags even if the [Flags] attribute is not present. Let’s take a non-flags enum like the ResultCode used earlier:
And if we run that through the same formats again we get:
Notice that since we had multiple values combined, but it was not a [Flags] marked enum, the G and default format gave us a number instead of a value name. This is because the value was not a valid single-value constant of the enum. However, using the F flags format string, it broke out the value into its component flags even though it wasn’t marked [Flags].
So, if you want to get an enum to display appropriately for whether or not it has the [Flags] attribute, use G which is the default. If you always want it to attempt to break down the flags, use F. For numeric output, obviously D or X are the best choice depending on whether you want decimal or hex.
Hopefully, you learned a couple of new tricks with using the Enum class today! I’ll add more little wonders as I think of them and thanks for all the invaluable input!
© Geeks with Blogs or respective owner