Associating
Strings with enums
Friday,
December 19, 2014
4:26 PM
I
have seen other great articles out lining the benefits of some pretty clever
and useful helper classes for enums. Many of these methods almost exactly
mirror methods I had written in my own EnumHelper class. (Isn't it crazy when
you imagine how much code duplication there must be like this out there!)
One
thing that I don't see emphasized much is trying to associated string values
with enums. For example, what if you want to have a Drop Down list that you can
choose from a list of values (which are backed by an enum)? Lets start with a
test enum:
public enum States
{
California,
NewMexico,
NewYork,
SouthCarolina,
Tennessee,
Washington
}
So
if you made a drop down list out of this enum, using the ToString() method, you
would get a drop down that looks like this:

While
most people will understand this, it should really be displayed like this:

"But
enums can't have spaces in C#!" you say. Well, I like to use the
System.ComponentModel.DescriptionAttribute to add a more friendly description
to the enum values. The example enum can be rewritten like this:
public enum States
{
California,
[Description("New Mexico")]
NewMexico,
[Description("New York")]
NewYork,
[Description("South Carolina")]
SouthCarolina,
Tennessee,
Washington
}
Notice
that I do not put descriptions on items where the ToString() version of that
item displays just fine.
How
Do We Get To the Description?
Good
question! Well, using reflection of course! Here is what the code looks like:
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
This method first looks for the presence of a DescriptionAttribute
and if it doesn't find one, it just returns the ToString() of the value passed
in. So GetEnumDescription(States.NewMexico);
returns
the string "New Mexico".
A
Free Bonus: How to Enumerate Enums
Ok,
so now we know how to get the string value of an enum. But as a free bonus, I
also have a helper method that allows you to enumerate all the values of a
given enum. This will allow you to easily create a drop down list based on an
enum. Here is the code for that method:
public static IEnumerable<T> EnumToList<T>()
{
Type enumType = typeof(T);
// Can't
use generic type constraints on value types,
// so have
to do check like this
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of
type System.Enum");
Array enumValArray = Enum.GetValues(enumType);
List<T> enumValList = new List<T>(enumValArray.Length);
foreach (int val in enumValArray)
{
enumValList.Add((T)Enum.Parse(enumType, val.ToString()));
}
return enumValList;
}
As
you can see, the code for either of these methods isn't too complicated. But
used in conjunction, they can be really useful. Here is an example of how we
would create the drop down list pictured above based on our enum:
DropDownList
stateDropDown = new DropDownList();
foreach (States state in EnumToList<States>())
{
stateDropDown.Items.Add(GetEnumDescription(state));
}
One
More Example
There
is one more scenario that I often find myself needing to associate string
values with enums - when dealing with legacy constant string based system. Lets
say you have a library that has the following method:
public void ExecuteAction(int value, string actionType)
{
if (actionType == "DELETE")
Delete();
else if (actionType == "UPDATE")
Update();
}
(I
tried to make this look as legacy as I could for a contrived example). What
happens if somebody passes in "MyEvilAction" as a value for
actionType? Well, whenever I see hard coded strings, that is a code smell that
could possibly point to the use of enums instead.
But
sometimes you don't have control over legacy code and you have to deal with it.
So you could make an enum which looks like this:
public enum ActionType
{
[Description("DELETE")]
Delete,
[Description("UPDATE")]
Update
}
(I
know, I know, this is a very contrived example) Then you could call the
ExecuteAction Method like this:
ExecuteAction(5, GetEnumDescription(ActionType.Delete));
This
at least makes the code more readable and may also make it more consistent and
secure.
0 komentar:
Posting Komentar