在没有指定案例可以处理的情况下,在switch语句中抛出异常 [英] Throwing exceptions in switch statements when no specified case can be handled

查看:214
本文介绍了在没有指定案例可以处理的情况下,在switch语句中抛出异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在过去的8年中,我一直在写C#,并且成为了相当的防御性OOP程序员。以静态类型的语言工作,您可以在方法中执行验证参数,并抛出异常,您将不会使用动态和更自由的语言。我认为自己是C#的专家,我正在寻找其他精通C#开发人员的最佳实践的反馈。



假设我们有一个功能来更改密码用户在MVC应用程序的系统中:

  public JsonResult ChangePassword 
(string username,string currentPassword,string newPassword )
{
switch(this.membershipService.ValidateLogin(username,currentPassword))
{
case UserValidationResult.BasUsername:
case UserValidationResult.BadPassword:
// abort:返回JsonResult与本地化的错误消息
//无效的用户名/传递组合。
case UserValidationResult.TrialExpired
// abort:返回带有本地化错误消息的JsonResult
//用户无法登录,因为他们的试用期已过期
case UserValidationResult.Success:
休息
}

//现在修改用户验证的密码
}

membershipService.ValidateLogin()返回一个 UserValidationResult 枚举,定义为:

 枚举UserValidationResult 
{
BadUsername,
BadPassword,
TrialExpired,
成功
}

作为一名防守程序员,我将更改以上 ChangePassword()方法抛出一个异常,如果有一个无法识别的 UserValidationResult 值从 ValidateLogin()

  public JsonResult ChangePassword 
(string username,string currentPassword,string newPassword)
{
switch(this.membershipService.ValidateLogin(username,currentPassword))
{
case UserValidationResult.BasUsername:
case UserValidationResult.BadPassword:
// abor t:返回JsonResult与本地化的错误消息
//无效的用户名/传递组合。
case UserValidationResult.TrialExpired
// abort:返回带有本地化错误消息的JsonResult
//用户无法登录,因为他们的试用期已过期
case UserValidationResult.Success:
休息
default:
throw new NotImplementedException
(Unrecognized UserValidationResult value);
//或NotSupportedException()
break;
}

//现在修改用户验证的密码
}

我一直认为最上面的代码片段是最佳做法。例如,如果一个开发人员要求现在用户尝试登录,如果是这样的 - 或者是商业原因,他们假设先是联系业务?所以 UserValidationResult 的定义更新为:

 枚举UserValidationResult 
{
BadUsername,
BadPassword,
TrialExpired,
ContactUs,
成功
}
/ pre>

开发人员更改了 ValidateLogin()方法的正文以返回新的枚举值( UserValidationResult.ContactUs )(如果适用),但忘记更新 ChangePassword()。没有交换机的例外,用户在登录尝试甚至不能首先被验证时仍然可以更改密码!



只是我或者是这个默认值:throw new Exception()一个好主意?我在几年前看到,总是(在深入研究之后)认为它是一个最佳实践。

解决方案

我总是抛出一个在这种情况下例外。考虑使用 InvalidEnumArgumentException ,这在这种情况下提供更丰富的信息。


I've been writing C# for the last 8 years and have become quite the defensive OOP programmer. Working in a statically-typed language, you do things like validate arguments in methods and throw exceptions where you wouldn't in languages that are dynamic and more liberal. I consider myself an expert in C# and am looking for feedback from other well-versed C# developers on best practices.

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.

解决方案

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

这篇关于在没有指定案例可以处理的情况下,在switch语句中抛出异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆