Enumerations can make your code much easier to read but there is one thing you should watch out for when using them. Before I get into what to watch out for let me define what an enumeration is. An enum type is a distinct value type with a set of named constants. An enum type that does not explicitly declare an underlying type has a type of int. So this means that by default an enum can have a range of values (constants) equivalent to an int. The set of values that an enum type can take on is not limited by the enum members. In fact any value of the underlying type of an enum can be cast to the enum type and is a distinct valid value of that enum type. These last statements are the basis for a Gotcha you need to watch out for when using enumerations.
The fact that an enum can be any valid type of the underlying type allows things like this to happen.
// Variable is created and assigned a value of ProductType.Commercial
ProductType productType = ProductType.Commercial;
// Variable is assigned a new value that is out of range
productType = (ProductType)100;
You need to keep this in mind when creating methods and properties that accept enumerations. Sure most of us use Visual Studio to create our applications and most of us would use the enum type instead of doing something odd like above but the fact you can do it can lead to some interesting results in your application. Here is an example of a method that doesn’t check for valid values.
/// <summary>
/// This method accepts a ProductType enum as a parameter and throws an exception if the
/// value is out of range.
/// </summary>
/// <param name=”type”>A valid ProductType enumeration</param>
static void AcceptProductType(ProductType type)
{
// The switch will not blow up if the value is not in range
switch (type)
{
case ProductType.HouseHold:
Console.WriteLine(“AcceptProductType Message: This is an enum with a value of ” + type.ToString());
break;
case ProductType.Commercial:
Console.WriteLine(“AcceptProductType Message: This is an enum with a value of ” + type.ToString());
break;
}
}
As you can see without checking the parameter this switch statement would never do anything if an invalid value was passed in. This could be resolved by using a default statement in the switch and throwing an exception but that could get messy if the method only worked with a few values of the enum. A better approach would be to check the parameter and throw an exception right at the top of the method like the following method.
/// <summary>
/// This method accepts a ProductType enumeration and validates that the parameter is
/// of type ProductType
/// </summary>
/// <param name=”type”>A valid ProductType enumeration</param>
static void AcceptProductTypeRevised(ProductType type)
{
// Check the parameter to see if the value is correct
if (Enum.IsDefined(typeof(ProductType), type) == false)
{
throw new ArgumentOutOfRangeException(“This value is not in the range for the enum type ProductType”);
}
// Do some work
AcceptProductType(type);
}
This approach identifies the issue right away and never lets the method execute if the parameter is incorrect. This type of defensive programming can save a lot of time when it comes to testing your code. I have included a sample console application that demonstrates this.