CantSleepAgain CantSleepAgain - 3 years ago 84
C# Question

Throwing exceptions in switch statements when no specified case can be handled

Let's say we have a function that changes a password for a user in a system in an MVC app.:

public JsonResult ChangePassword
(string username, string currentPassword, string newPassword)
{
switch (this.membershipService.ValidateLogin(username, currentPassword))
{
case UserValidationResult.BasUsername:
case UserValidationResult.BadPassword:
// abort: return JsonResult with localized error message
// for invalid username/pass combo.
case UserValidationResult.TrialExpired
// abort: return JsonResult with localized error message
// that user cannot login because their trial period has expired
case UserValidationResult.Success:
break;
}

// NOW change password now that user is validated
}


membershipService.ValidateLogin()
returns a
UserValidationResult
enum that is defined as:

enum UserValidationResult
{
BadUsername,
BadPassword,
TrialExpired,
Success
}


Being a defensive programmer, I would change the above
ChangePassword()
method to throw an exception if there's an unrecognized
UserValidationResult
value back from
ValidateLogin()
:

public JsonResult ChangePassword
(string username, string currentPassword, string newPassword)
{
switch (this.membershipService.ValidateLogin(username, currentPassword))
{
case UserValidationResult.BasUsername:
case UserValidationResult.BadPassword:
// abort: return JsonResult with localized error message
// for invalid username/pass combo.
case UserValidationResult.TrialExpired
// abort: return JsonResult with localized error message
// that user cannot login because their trial period has expired
case UserValidationResult.Success:
break;
default:
throw new NotImplementedException
("Unrecognized UserValidationResult value.");
// or NotSupportedException()
break;
}

// Change password now that user is validated
}


I always considered a pattern like the last snippet above a best practice. For example, what if one developer gets a requirement that now when users try to login, if for this-or-that business reason, they're suppose to contact the business first? So
UserValidationResult
's definition is updated to be:

enum UserValidationResult
{
BadUsername,
BadPassword,
TrialExpired,
ContactUs,
Success
}


The developer changes the body of the
ValidateLogin()
method to return the new enum value (
UserValidationResult.ContactUs
) when applicable, but forgets to update
ChangePassword()
. Without the exception in the switch, the user is still allowed to change their password when their login attempt shouldn't even be validated in the first place!

Is it just me, or is this
default: throw new Exception()
a good idea? I saw it some years ago and always (after groking it) assume it to be a best practice.

Answer Source

I always throw an exception in this case. Consider using InvalidEnumArgumentException, which gives richer information in this situation.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download