Enumerators - API Design

I love using enumerators! API developers should do all they can do to include them in method signatures so the API consumer can take advantage of all the wonders of intellisense.

I have recently found a pitfall that API developers have fallen into repeatedly when it comes to the use and type safety of enumerators in method signatures. If we consider the following enumerator and also a method that uses it, we can assume that the developer intended to use Direction and only have 4 valid values associated with it.

public enum Direction
{
	North,
	South,
	East,
	West
}

public static void WhichDirection(Direction number)
{
	//Here we need to process values 0,1,2,3 as defined by 'Direction' 
	//anything else is not valid
}

What I have noticed is that in this scenario API developers can assumes that the WhichDirection method requires no additional type checking as they have a defined enumerator. However, the following examples shows how the API consumer can abuse the method and its expected input.

WhichDirection(Direction.North);    //expected input
WhichDirection(Direction.South);    //expected input
WhichDirection(Direction.East);     //expected input
WhichDirection(Direction.West);     //expected input
WhichDirection((Direction)59);      //a little skulduggery, that the compiler will not catch!

Clearly WhichDirection needs to be able to detect this scenario and react appropriately. If you have defined only 4 enumerated values and that is literally all that should be passed then the following is one way to safely check for that.

public static void WhichDirection(Direction number)
{
	if (Enum.IsDefined(typeof(Direction), number))
	{
		//
	}
	else 
	{
		throw new ArgumentOutOfRangeException();
	}
}

The key here is not assume enumerators just keep you safe from the outside world, enumerators provide API consumers with a great pattern to follow. API developers need to assume that there is malicious (or ignorant) intent when developers consume their API.

n.b. IsDefined may not always be the best way to solve this problem, I believe it uses reflection and is notoriously slow.

Technorati tags: ,


Comment Section

Comments are closed.