关于c#:throw new Exception vs Catch block


throw new Exception vs Catch block

以下是否有任何行为差异:

1
2
3
4
if (s == null) // s is a string
{
 throw new NullReferenceException();
}

和:

1
2
3
4
5
6
7
8
9
try
{
  Console.Writeline(s);
}


catch (NullReferenceException Ex)
{ // logic in here
}

如果s为null,则抛出null对象的异常。 第一个示例更具可读性,因为它准确显示了错误发生的位置(异常位就在导致异常的行旁边)。

我已经通过各种技能水平的各种编码器在各种博客上看到了这种编码风格,但为什么不通过检查s是否为空来执行主逻辑,从而保存异常以免被引发? 这种方法有不利之处吗?

谢谢


不,Console.WriteLine(null)不会抛出异常。它只会打印出来。现在假设您的意思是:

1
Console.WriteLine(s.Length);

那么它有意义......你应该使用第一种形式。当您无法使用当前信息提前预测时,应该会出现例外情况。如果你能够轻易解决出错的问题,那么尝试一定会失败的操作是没有意义的。它导致代码更难理解并且表现更差。

所以NullReferenceExceptionArgumentNullException之类的东西不应该被捕获,除非它们是由于一个令人讨厌的API,它有时会抛出你可以处理的异常,但是它们本来不应该被抛出。这就是为什么在Code Contracts中,失败的契约的默认行为是抛出一个你无法明确捕获的异常,除了捕获所有东西(通常位于堆栈顶部的某个位置)。


正如Jon Skeet已经提到的,Console.WriteLine (null)不会抛出异常。

接下来,我想说你应该'快速失败'。这意味着你必须在你的方法中放入'guard'子句,并检查你的方法中给出的参数,如果它们可以被认为是有效的。
这允许您自己抛出异常,并提供一条在调试时有用的附加消息。该消息可以清楚地指出错误,如果你遇到一个NullReferenceException而它没有任何好的信息在它的message属性中,那就更容易了。


Jon Skeet是对的,但更一般地说,这都是语义问题。

如果情况具有一些应用意义(数字超出范围,未来出生日期等),您可能需要在执行任何操作之前测试它并抛出自定义异常(对您的应用程序有意义)。

如果情况真的是"例外",只需编写代码,就像给定值是正确的一样。请参阅,如果您进行测试,您将每次都执行此操作,因为知道VM无论如何都会执行此操作,以防它需要抛出异常。从性能的角度来看,如果错误发生在统计上较小的发生,那就没有意义了。


如果您正在编写类库,可能有时您知道如果某个参数包含空值,则可能会导致进一步的麻烦。在这些情况下,我通常发现抛出异常是个好主意(即使我可能会使用ArgumentNullException),以使类库的用户尽可能早地清楚地意识到这一点。

例外并不总是坏事。


如果您采用Design By Contract类型方法处理事物,那么一段代码可以指定它抛出异常以指定其合同并强制执行它。当然,另一半是调用代码来识别合同并履行合同。

在这种情况下,如果你知道一个方法在传入null时抛出异常(即它的合同是你没有传递空值),那么你应该在调用之前检查它。

Jon Skeet表示,该方法无论如何都不会抛出异常。这可能是也可能不是,但保护方法合同的原则(我相信这是你的问题的重点)。