捕获 NullReferenceException 还是先测试 Nothing?
我们有一个属性,其工作是查找描述。如果查找失败,它应该显示一个空字符串。
所以我们可以像这样编写属性:
If foo.bar Is Not Nothing Then
Return foo.bar.Description
Else
Return String.Empty
End If
但这涉及执行 foo.bar 两次,如果这样做代价高昂,那么可能更好:
Dim b As bar = foo.bar
If b IsNot Nothing Then
Return b.Description
Else
Return String.Empty
End If
但实际上我们想要做的就是将任何类型的错误视为空描述。所以在某些方面这更简单:
Try
Return foo.bar.Description
Catch e As NullReferenceException
Return String.Empty
End Try
但是仅仅捕获并忽略错误是否存在任何问题(性能,纯度,其他?)?
您有时会读到抛出异常的成本很高,但我不确定作者的意思是否是使用 Throw
关键字(我没有这样做)构建异常的成本很高,或者他是否意味着允许异常发生的成本很高(就像我会做的那样)。
We have a property whose job is to look up a description. If the lookup fails it should show an empty string.
So we can code the property like this:
If foo.bar Is Not Nothing Then
Return foo.bar.Description
Else
Return String.Empty
End If
But that involves executing foo.bar twice, and if doing so is expensive, it's probably better like this:
Dim b As bar = foo.bar
If b IsNot Nothing Then
Return b.Description
Else
Return String.Empty
End If
But really all we want to do is treat any kind of error as an empty description. So in some ways this is simpler:
Try
Return foo.bar.Description
Catch e As NullReferenceException
Return String.Empty
End Try
But are there any problems (performance, purity, other?) with just catching and ignoring the error?
You sometimes read it's expensive to throw an exception but I am not sure whether the author means it's expensive to build in exceptions using the Throw
keyword (which I am not doing) or whether he means it's expensive to allow exceptions to occur (as I would be doing).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果肯定会测试
Nothing
而不是在这里依赖异常。您的代码表明foo.bar
为Nothing
的场景是预期场景,而不是例外场景。这样就给出了答案。抛出异常是一个相对昂贵的操作(从性能角度来看)。无论您是在代码中还是在库代码中抛出它,情况都是如此;这是完全相同的操作。然而,出于性能原因,我不会避免抛出异常,除非我有一个真实的、经过衡量的、关键的业务案例。
在我看来,这主要是一个表达意图的问题;通过测试
Nothing
并优雅地执行操作,您的代码表明了这样一个事实:发生这种情况并不奇怪。如果您担心执行两次
foo.bar
的性能,首先要做的就是查明情况是否确实如此。如果是这样,可能有一些方法可以解决这个问题(您的代码示例已经包含建议)。If would definitely test for
Nothing
instead of relying on exceptions here. You code indicates that the scenario wherefoo.bar
isNothing
is an expected scenario, and not an exceptional one. That sort of gives the answer.Throwing an exception is a relatively expensive operation (from a performance perspective). This is the case regardless of wheter you are throwing it in your code, or if it is thrown in library code; it's exactly the same operation. However, I would not keep from throwing exceptions for performance reasons unless I had a real, measured, critical business case.
In my opinion this is mostly a matter of showing intent; by testing for
Nothing
and acting gracefully on that, your code expresses the fact that this is not a strange thing to happen.If you are worried about the performance in executing
foo.bar
twice, the first thing to do is to find out if that is really the case. If so, there are probably ways of solving that (your code sample already contains a suggestion).我会采用这种方法:
如果以后发现自己经常重复代码的同一部分,您可以将此查找包装到通用函数中,例如:
这是一个用法示例:
假设您有一个类似的类,它将起作用在当前范围内声明:
就捕获异常的成本而言,这里是我对另一个问题的回答的链接 。它让您了解捕获异常如何影响调试性能以及发布版本的性能。从语义上讲,如果是非异常情况,最好避免抛出异常,正如其他答案中已经提到的那样。
I would go with this approach:
If later find yourself repeating the same portion of the code often, you can wrap this lookup into a generic function, such as this:
Here is a usage example:
It will work, assuming you have a similar class declared in the current scope:
As far as the cost of catching exceptions, here is a link to my answer on a different question. It gives you an idea of how catching exception impacts debugging performance and that of your Release build. Semantically, you better avoid throwing exceptions if it's non-exceptional situation, as already mentioned in other answers.
当您期望将其作为受控条件时,您应该始终尝试进行任何测试,仅在可能的情况下使用捕获来处理不需要的错误(我广泛使用不需要的错误,因为某些错误会产生想要的结果)。能够在不捕获异常的情况下处理空字符串,因此请使用它。
在 String 类类型中使用名为
IsNullOrEmpty
或IsNullOrWhiteSpace
的空字符串测试函数:这将允许您将异常处理留给意外异常(因为它应该是 ^^ )
从您的选择来看,第二个最接近我的建议,将您的函数结果放入一个保存变量中,然后使用 String.IsNullOrEmpt 测试该变量,或者如果您想包含空格检查然后
String.IsNullOrWhiteSpace
(这也测试空字符串)。这是运行的代码:
http://ideone.com/CelDe
You should always try testing for nothing when you are expecting it as a controlled condition, only use catches where possible to handle unwanted errors (I use unwanted broadly as some errors produce wanted results). The ability to handle null strings without catching an exception is there so use it.
Use an empty string test function within the String class type called
IsNullOrEmpty
orIsNullOrWhiteSpace
:This will allow you to leave your Exception handling for unexpected exceptions (as it should be ^^ )
In perspective of your choices, the second one is closest to what I would recommend, put your functions result into a holding variable, then test this variable using
String.IsNullOrEmpt
y or if you want to include whitespace checking thenString.IsNullOrWhiteSpace
(this also tests for empty strings too).Here is the code running:
http://ideone.com/CelDe