Intro

So enums are awesome. They greatly simplify your ability to restrict data fields in clear and self-descriptive way. The C# implementation of enums have alleviated the need for all of those awful “item code”, magic number, and random unenforced constants that can be the source of so many bugs.

However, nothing is perfect, and so there can some rough edges when working with enums. Everyone ends up writing the bunch of plumbing code, or taking shortcuts that are not as type-safe as they could be. MMDB encountered this on several projects at the same time, so we put it all in a helper library (yes, this met our rigid definition of worthwhile reusability). Recently we put this up on github (https://github.com/mmooney/MMDB.Shared) and NuGet (http://nuget.org/packages/MMDB.Shared), so please help yourself.

Is this groundbreaking? Absolutely not. In fact, some may not even consider it all that useful.  But it’s been helpful for us, and it’s one of the first NuGet packages I pull into each new application, so hopefully it can help others simplify some of their code.

Anyhow, let’s get down to it. We’ll run through the problems we encountered with enums, and what we’ve done to solve them.

Parsing Enums

One of the most annoying things with enums is trying to parse random input into a strictly typed enum value. Say you have a string that has come from a database or user input, and you think the value should align nicely. You end up with something like this:

string input = "SomeInputValue";
var enumValue = (EnumCustomerType)Enum.Parse
                 (typeof(EnumCustomerType), inputValue);

 

Ugh. First, you have to pass in the type and cast the result, which is ugly, and should never be necessary since generics were introduced in .NET 2.0. Also, you have to hope that “SomeInputValue” is a valid value for the enum, otherwise you get a wonderful System.ArgumentException, with a  message like “Additional information: Requested value ‘SomeInputValue’ was not found.”, which is moderately helpful.

In .NET 4, we finally got introduced a strictly-typed Enum.TryParse:

string input = "SomeInputValue";
EnumCustomerType enumValue;
if(Enum.TryParse<EnumCustomerType>(input, out enumValue))
{
//...
}

This is much better, but can still be a little clunky.  You have to play the temporary variable game that all .NET TryParse methods require, and if you want to actually throw a meaningful exception you are back to calling Enum.Parse or writing the check logic yourself.

So lets try to simplify this a little with the EnumHelper class in MMDB.Shared.  Our basic Parse is nice and concise:

string input = "SomeInputValue";
var enumValue = EnumHelper.Parse<EnumCustomerType>(input);

And if this is not a valid value, it will throw a exception with the message “Additional information: Unrecognized value for EnumCustomerType: ‘SomeInputValue’”.  I always find a little more helpful to have exceptions tell you exactly what it was trying to do when it failed, not just that it failed.

Also, it has a strictly typed TryParse method, that does not require any temp values.  It returns a nullable enum, with which you can do whatever you like:

string input = "SomeInputValue";
EnumCustomerType? enumValue = 
             EnumHelper.TryParse<EnumCustomerType>(input);
return enumValue.GetValueOrDefault
             (EnumCustomerType.SomeOtherInputValue);

Enum Display Values

The next problem we run into assigning display values to enums, and more importantly easily retrieving them.

OK, so this has been done a few times.  In most cases, people have used the System.ComponentModel.DescriptionAttribute class to assign display values to enums:

public enum EnumCustomerType 
{
    [Description("This is some input value")]
    SomeInputValue,
    [Description("This is some other input value")]
    SomeOtherInputValue
}

Also the MVC folks introduced a DisplayAttribute in System.ComponentModel.DataAnnotations:

public enum EnumCustomerType 
{
	[Display("This is some input value")]
	SomeInputValue,
	[Display("This is some other input value")]
	SomeOtherInputValue
}

So lots of options there, with lots of dependencies.  Anyhow, to keep it minimal, we created a simple class specifically for enum display values:

public enum EnumCustomerType 
{
	[EnumDisplayValue("This is some input value")]
	SomeInputValue,
	[EnumDisplayValue("This is some other input value")]
	SomeOtherInputValue
}

What’s fun about this is that you can now get your display value in a single line:

public enum EnumCustomerType 
{
	[EnumDisplayValue("This is some input value")]
	SomeInputValue,
	[EnumDisplayValue("This is some other input value")]
	SomeOtherInputValue
}
//...
//Returns "This is some input value"
string displayValue = EnumHelper.GetDisplayValue
                       (EnumCustomerType.SomeInputValue);

And if you don’t have an EnumDisplayValue set, it will default to the stringified version of the enum value:

public enum EnumCustomerType 
{
	[EnumDisplayValue("This is some input value")]
	SomeInputValue,
	[EnumDisplayValue("This is some other input value")]
	SomeOtherInputValue,
	SomeThirdValue
}
//...
//Returns "SomeThirdValue"
string displayValue = EnumHelper.GetDisplayValue
                        (EnumCustomerType.SomeThirdValue);

Databind Enums

Next, let’s do something a little more useful with the enums.  Let’s start databinding them.

Normally if you want to display a dropdown or a radio button list or other type of list control to select an enum, you either have to manually create all of the entries (and then make sure they stay in sync with the enum definition), or write a whole bunch of plumbing code to dynamically generate the list of enum values and bind them to the control.  And if you want to include display values for your enums, it’s even worse, because you have to map the enum values and display values into object that exposes those fields to the DataTextField and DataValueField in the  list control.  Meh.

Or, you can just do this:

EnumHelper.DataBind(dropDownList, typeof(EnumCustomerType));

This will retrieve the the enum values, and their display values, put them into a list, and bind it to the control.

I know what you’re going to say.  “But I want to hide the zero enum value because that is really the ‘None’ value”:

EnumHelper.DataBind(comboBox, typeof(EnumCustomerType), 
             EnumHelper.EnumDropdownBindingType.RemoveFirstRecord);

Or, “I want to display the first zero record in my combobox, but I want to clear it out because it’s not a real valid selection, it’s just the default”:

EnumHelper.DataBind(comboBox, typeof(EnumCustomerType), 
             EnumHelper.EnumDropdownBindingType.ClearFirstRecord);

Or even, “yeah I want that blank first record in my combobox, but I don’t have a zero/none value defined in my enum values, so I want to add that when databinding”:

EnumHelper.DataBind(comboBox, typeof(EnumCustomerType), 
             EnumHelper.EnumDropdownBindingType.AddEmptyFirstRecord);

Conclusion

So again, nothing groundbreaking here.  Hey, it may not even be the best way to handle some of this stuff.  But it works great for us, removes a lot of the unnecessary noise from our code, and makes it a lot easier to read our code and get to the intent of what is being down without a whole lot of jibber-jabber about the how.

Hopefully this can make one part of your coding a lot easier.  Any feedback or suggestions welcome, or better yet, submit a patch Smile