Introduction
Enums are great programming tools. They let you define groups of integral based constants that can be accessed elsewhere throughout your code in a strongly typed and symbolic fashion. The most obvious benefit of enums is their inherent catering to the rapid development model.
The Dilemma
The .NET library comes with a static class for enum management, System.Enum
. Let's interrogate the method declarations provided by Enum
:
object Enum.Parse(type, string)
object Enum.ToObject(type, object)
string Enum.GetName(type, object)
string[] Enum.GetName(type)
Array Enum.GetValues(type)
bool Enum.IsDefined(type, object)
Type Enum.GetUnderlyingType(type)
string Enum.Format(type, value, string)
Despite the wonderful functionality System.Enum
provides us, it is not without its drawbacks. The first thing you should notice is that each method requires you to pass the type of enum that you wish to reference — not the enum itself, but the type of the enum. This means you have to encase the enum name within the typeof()
system method. The second thing you should notice is that the Parse
and ToObject
methods return a type of object — this would require us to perform an explicit cast on the returned object to transform it into the designated enum object. This explicit cast resolves into a non-type-safe expression, as well as extra processing overhead.
Let's look at an example. Assume we have an enum called OrderStatus
which defines four possible states: Open
, Submitted
, Shipped
, and Invoiced
.
public enum OrderStatus
{
Open = 0,
Submitted = 1,
Shipped = 2,
Invoiced = 3
}
Now, let's assume a customer wants to see all the orders that have been shipped. When the customer sends their request through, your server-side code parses the form collection if it is a POST request, or querystring if its a GET, and determines the order status filter chosen. Normally, if we want to put their choice in the form of a strongly typed enum object, we have to perform an explicit cast that looks like this:
protected void Page_Load(object sender, EventArgs e)
{
NameValueCollection userData = Request.HttpMethod.ToUpper() ==
"GET" ? Request.QueryString : Request.Form;
OrderStatus orderStatus =
(OrderStatus)Enum.Parse(typeof(OrderStatus), userData["oStatus"]);
}
Now, this isn't too terrible looking, but imagine working with a multitude of enums within the same code block — it's going to get a little messy, and typing out typeof(MyEnum)
many times over will become rather tedious and exhausting.
The Solution
The solution is incredibly simple — we will write a wrapper class that will make use of Generics to handle our enum needs in a type-safe manner. If you're not familiar with Generics, a quick explanation: they allow your classes and methods to perform operations on non-specific types, hence the term "generic". The most common use of Generics used in .NET are the Collection objects, such as List<>
and Dictionary<>
. After defining our Generics-supported class, all that is left to do is to implement the methods. Here is what our class should look like:
public static class StrongEnum<T>
{
public static T Parse(string value)
{
return (T)Enum.Parse(typeof(T), value);
}
public static T Parse(string value, bool ignoreCase)
{
return (T)Enum.Parse(typeof(T), value, ignoreCase);
}
public static T ToObject(object value)
{
return (T)Enum.ToObject(typeof(T), value);
}
public static string GetName(object value)
{
return Enum.GetName(typeof(T), value);
}
public static string[] GetNames()
{
return Enum.GetNames(typeof(T));
}
public static Array GetValues()
{
return Enum.GetValues(typeof(T));
}
public static bool IsDefined(object value)
{
return Enum.IsDefined(typeof(T), value);
}
public static Type GetUnderlyingType()
{
return Enum.GetUnderlyingType(typeof(T));
}
public static string Format(object value, string format)
{
return Enum.Format(typeof(T), value, format);
}
}
Now, we can write cleaner, strongly-typed enum operations:
protected void Page_Load(object sender, EventArgs e)
{
NameValueCollection userData = Request.HttpMethod.ToUpper() ==
"GET" ? Request.QueryString : Request.Form;
OrderStatus orderStatus =
StrongEnum<OrderStatus>.Parse(userData["oStatus"]);
}