使用异常进行流量控制

Yip*_*Yay 7 language-agnostic exception-handling exception

我最近被告知我滥用异常来控制应用程序中的流量,所以我这是我试图以某种方式澄清情况.

在我看来,一个方法应该在遇到情况时抛出异常,这种情况无法在内部处理或者可能由调用方更好地处理.


那么 - 是否存在任何特定的规则集,可用于在开发应用程序时回答以下问题:

  • 什么时候应该抛出一个异常,什么时候应该编写具有强大的nothrow保证的代码,这可能只是返回 bool表示成功或失败?

  • 我应该尝试最小化情况的数量,当方法抛出异常时,或者相反,它应该最大化以在处理这些情况时提供灵活性吗?

  • 我应该坚持在开发我的应用程序时使用的框架/运行时设置的异常抛出约定,还是应该包装所有这些调用,以便它们匹配我自己的异常抛出策略?

  • 我还建议使用错误代码进行错误处理,这似乎非常有效,但从语法的角度来看很丑陋(同样,当使用它们时,开发人员失去了为方法指定输出的能力).你怎么看待这件事?


实施例第三个问题(I用的I/O架构和遇到以下情况):

所描述的框架不使用异常来处理错误,但其他代码确实使用它们.我是否应该将所有可能的失败包裹起来'???'并在这种情况下抛出异常?或者我应该将方法的签名更改为bool PrepareTheResultingOutputPath仅指示操作是否成功?

public void PrepareTheResultingOutputFile(
    String templateFilePath, String outputFilePath)
{
    if (!File.Exists(templateFilePath))
        // ???

    if (!Directory.MakePath(outputFilePath))
        // ???

    if (File.Exists(outputFilePath))
        if (!File.Remove(outputFilePath))
            // ???

    if (!File.Copy(templateFilePath, outputFilePath)
        // ???
}
Run Code Online (Sandbox Code Playgroud)

另一个例子 - 即使.NET Framework不遵循一些严格的异常抛出策略.一些方法被记录为抛出10多种不同的异常类型,包括普通的异常类型NullArgumentException,但其中一些只是返回bool以指示操作的成功或失败.

谢谢!

Ada*_*cin 5

异常的问题在于它们本质上是美化的 goto,能够展开程序的调用堆栈。因此,如果您“使用异常进行流量控制”,那么您可能将它们用作 goto 而不是异常条件的指示。这正是例外的要点,也是其名称的原因:它们应该仅在例外情况下使用。因此,除非一个方法被设计为不抛出异常(.NET 就是一个例子int.TryParse),否则可以抛出异常来响应异常情况。

与 Java 相比,C# 的优点在于,在 C# 中,您基本上可以通过返回元组类型或使用 out 参数来返回两个或多个值。因此,返回错误代码作为方法的主要返回值并没有太多丑陋之处,因为您可以使用 out 参数来完成其余的操作。例如,调用的常见范例int.TryParse

string s = /* Read a string from somewhere */;
int n;
if (int.TryParse(s, out n))
{
    // Use n somehow
}
else
{
    // Tell the user that they entered a wrong number
}
Run Code Online (Sandbox Code Playgroud)

现在回答你的第三个问题,这似乎是最重要的。参考您的示例代码,您询问是否应该返回bool来指示成功/失败,或者是否应该使用异常来指示失败。不过,还有第三种选择。您可以定义一个枚举来告诉方法如何失败,并将该类型的值返回给调用者。然后,调用者有一个广泛的选择:调用者不必使用一堆 try/catch 语句,也不必使用 if 来了解方法如何失败,但可以选择编写其中之一

if (PrepareTheResultingOutputFile(templateFilePath, outputFilePath) == Status.Success)
    // Do  something
else
    // It failed!
Run Code Online (Sandbox Code Playgroud)

或者

switch (PrepareTheResultingOutputFile(templateFilePath, outputFilePath))
{
    case Status.Success:
        // Do something
        break;
    case Status.FileNotPresent:
        // Do something else
        break;
    case Status.CannotMakePath:
        // Do something else
        break;
    // And so on
    default:
        // Some other reason for failure
        break;
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处此处找到有关此问题的更多信息,特别是在我强烈推荐的Joel Spolsky 的帖子中。


归档时间:

查看次数:

1943 次

最近记录:

7 年,11 月 前