【问题标题】:Is returning an unthrown exception a bad practice for validating input?返回未引发的异常是否是验证输入的坏习惯?
【发布时间】:2012-03-16 05:22:16
【问题描述】:

为了输入验证的目的编写返回未引发异常的方法是一种不好的做法吗?如果输入有效,Validate 方法将返回 null,或者如果输入实际提交,则返回将引发的异常。

public Exception Validate(object input)
{
    if (!SomeParametersMatch(input))
        return new SomeException("Message...");
    if (!SomeOtherParametersMatch(input))
        return new SomeOtherException("Another message...");

    // More cases here...

    return null;
}

这样,您可以使用相同的函数来验证输入、向用户显示响应以及在代码中引发异常:

public void Submit(object input)
{
    Exception ex = Validate(input);
    if (ex != null) throw ex;

    // Do whatever action here...
}

例如,如果您使用函数来标记可单击的空格,则可以为每个空格调用Validate,如果返回值不为空,则将它们标记为有效。然后 Submit 仅在用户实际单击空间并最终确定选择时才被调用。当您需要确保输入在您选择时有效时,这将消除代码重复。

我可以让 Validate 返回一个 void 并简单地抛出异常,但由于 catching thrown exceptions is the most part of exception throwingValidate 将在比有效输入更多的无效输入上运行,看起来像浪费。如果 Validate 仅在用户实际提交数据时使用,那么使用 try/catch 块我不会有问题。但由于它被用于过滤呈现给用户的数据,因此在大多数情况下抛出异常,只是为了捕获和丢弃它,似乎非常浪费。

【问题讨论】:

  • // Do whatever action here... 中的代码如果您需要在第一次抛出异常时抛出,则不会执行。
  • 仅当输入无效时。如果有效,Validate 将返回 null,Submit 函数将运行。
  • 对我来说这看起来很奇怪;基本上,您似乎用return 替换了throw。这真的值得努力吗?缺点是你必须记得扔到外面Validate()。把Validate()扔进去可以帮助你,以防你忘记了。

标签: .net exception-handling


【解决方案1】:

哪里说 try-catch 块很贵?返回异常有什么好处?

public void Validate(object input)
{
    if (!SomeParametersMatch(input))
        throw new Exception("Message...");
    if (!SomeOtherParametersMatch(input))
        throw new Exception("Another message...");

    // More cases here...

}

public void Submit(object input)
{
    Validate(input);

    // Do whatever action here...
}

此代码更具可读性且不易混淆。这正是使用异常的方式。使用 try-catch 块的任何费用都可以忽略不计。

【讨论】:

  • 我希望Validate 能够在许多无效输入上运行,以便在用户提交之前将它们清除。 try 的成本可以忽略不计,但捕获抛出的异常需要相当多的工作。见stackoverflow.com/questions/867017/…
  • 除非您同时验证数百万个输入,否则用户在捕获异常时不会体验到明显的延迟。除此之外,无论如何你都会在 Submit 方法中抛出异常。
  • 我正在验证游戏循环内游戏板上的空间。是的,它是从Submit 抛出的,但每回合只调用一次。 (假设输入有效。)
  • 如果Validate 抛出异常,每次调用Submit 仍然只会抛出一个异常。除非Submit 捕获到异常,否则抛出的异常将突破ValidateSubmit 方法,阻止进一步的验证发生。尝试使用上面的代码并提交一个包含许多无效输入的测试用例。如果 Submit 在 try-catch 中,您将只能捕获任何方法调用引发的第一个异常。
  • 我的回答是:这是不好的做法。在您的情况下,最好的办法是尝试这两个选项并为它们计时。
【解决方案2】:

像 DataAnnotations 这样的验证库是一种解决方法,而不是处理用户输入验证的正确方法。最好的方法是从设置的每个属性中验证值。

DataAnnotations 和相应的验证库的副作用是所有对象在对象被验证之前都处于不一致的状态。属性设置器内部的验证没有同样的问题。

但是,有时使用此类库是最好的方法。 但不是每次。确保它是正确的设计选择。

话虽如此,我会在验证方法中建立一个验证错误列表,然后抛出一个异常,包括所有错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    相关资源
    最近更新 更多