抛出新异常 vs 捕获块

9

这两种方式之间是否有行为上的区别:

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

并且:

try
{
  Console.Writeline(s);
}


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

如果s为空,两个都会抛出null对象的异常。第一个示例更易读,因为它准确地显示了错误发生的位置(异常位紧挨着将导致异常的行)。
我已经在各种博客上看到过很多不同技能水平的程序员使用这种编码风格,但为什么不通过检查s是否不为空来执行主逻辑,从而避免引发异常呢?这种方法有什么缺点吗?
谢谢
5个回答

18
不,Console.WriteLine(null)不会抛出异常。它只是什么也不输出。现在假设你的意思是:
Console.WriteLine(s.Length);

如果你能够轻松地发现错误,那么就没有意义去尝试一个注定会失败的操作。这会导致代码更难理解并且性能更差。因此,除非有一些恶劣的API偶尔会抛出异常,你可以处理它们,但实际上这些异常不应该被抛出,否则不应该捕获NullReferenceExceptionArgumentNullException等异常。这就是为什么在Code Contracts中,失败的合同的默认行为是抛出一个你无法显式捕获的异常,除了通过捕获所有异常(通常在堆栈的顶部)。

谢谢。我的意思是任何变量在方法/构造函数中使用时,会导致NullReferenceException或对象引用未设置为对象实例的错误。一个编码朋友告诉我,第一种形式应该由调用者捕获异常?所以如果我有另一个方法调用第一种形式,并且有一个捕获抛出异常行的catch块。你同意吗? - GurdeepS
如果有的话,"对象引用未设置到对象实例"和"NRE"之间是否存在关联? - GurdeepS
你如何知道异常是否会被调用者捕获? 当某些事情出错时,显式抛出异常(这更具信息性)和让.NET框架抛出通用的NullRef异常有什么区别? - Frederik Gheysels
3
这个?http://blogs.msdn.com/ericlippert/archive/2008/09/10/vexing-exceptions.aspx - Eric Lippert
1
引用框架设计准则,“不要允许公开可调用的API显式或隐式地抛出NullReferenceException…” 另请参见http://blogs.msdn.com/brada/archive/2004/07/11/180315.aspx - TrueWill
我曾经搜索过“vexatious exceptions”而不是“vexing exceptions”。接近但不完美。 - Jon Skeet

2

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

除此之外,我想说的是你应该“快速失败”。这意味着你必须在方法中放置“守卫”条款,并检查方法中给定的参数是否可以被视为有效。

这样可以让你自己抛出异常,并提供附加消息,这在调试时非常有帮助。这个消息可以清楚地指示出错的原因,比面对一个没有任何有用信息的NullReferenceException要方便得多。


1
如果您正在编写一个类库,可能会有这样的情况:如果某个参数包含空值,那么在后续操作中可能会出现问题。在这种情况下,我通常认为抛出异常是一个好主意(即使我可能会针对该情况使用ArgumentNullException),以便尽早、清晰地让类库的用户知道这一点。
异常并不总是坏事。

1

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

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

如果情况真的是“异常”,则只需将代码编写为如果给定值是正确的。看,如果你进行测试,那么你每次都会这样做,知道VM在需要抛出异常时也会这样做。从性能的角度来看,如果错误发生的统计发生率很低,这是没有意义的。


0
如果您采用设计契约的方法,那么一段代码可以指定它抛出异常以指定其契约并强制执行。另一半是调用代码认识到契约并履行它。
在这种情况下,这意味着如果您知道一个方法将在传递null时抛出异常(即它的契约是您不传递null),那么您应该在调用之前进行检查。
Jon Skeet说该方法不会抛出异常。这可能是真的,也可能不是,但是保护方法契约的原则仍然存在(我相信这就是您问题的重点)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接