假设我有以下类层次结构:
Person对象包含Customer对象,Customer对象包含Address对象。
我不在乎客户是否有地址,但如果有,我想将其保存到数据库中。所以在这种情况下,有这样的东西是完全没问题的:
try
{
Address addr = person.Customer.Address;
db.SaveAddress(addr);
}
catch
{
//I don't care, but if it is there, just save it.
}
在上面,我不在乎Customer是null还是Address为null。我有另一种选择
if(person.Customer != null)
{
if(person.Customer.Address != null)
{
}
}
如果层次结构很长,则上述情况可能会很长。是否有更优雅的方法来检查对象链是否为空而不必检查每个对象。
答案 0 :(得分:5)
对于特殊情况,您应始终使用例外。您将受到性能损失,因为CPU上会有一些上下文切换。
您可以将第二个示例与大多数短路语言合并为一行。
if(person.Customer != null && person.Customer.Address != null)
{
}
示例:
bool isAddressValid = person.Customer != null && person.Customer.Address != null;
if (isAddressIsValid) { }
答案 1 :(得分:3)
让您的代码检查条件有几个原因,而不仅仅是捕获任何异常并忽略它。想到的前两个是:
与其他人提到的一样,使用异常会产生非常高的性能成本(实际抛出异常时)。对于有效且常见的情况,您通常更愿意通过某些条件或方法返回值来指示错误。
即使您通过捕获异常来检测可能的条件,也建议抛出特定的异常类型,并且只捕获您允许的异常类型。因为如果出现其他问题并且引发了不同的异常怎么办? (例如,如果通过OutOfMemoryException
保存怎么办?你会抓住并忽略它)。在你的情况下,即使你去捕捉并忽略异常,最好只捕获NullReferenceException
,而忽略其余的。更好的是定义你自己的异常类型(例如CustomerHasNoAddressException
)并且只捕获它。
答案 2 :(得分:2)
你应该总是检查null
(或任何条件),如果你知道它可能发生,你可以避免异常,原因是异常缓慢,正如你所指出的那样,不优雅。只需使用:
if(person.Customer != null && person.Customer.Address != null) {
// ...
}
答案 3 :(得分:2)
这是非常糟糕的使用的例外情况。有时会出现“可疑”和“偷偷摸摸”的地方,但这只是彻头彻尾的...... 坏
这很糟糕,因为你在其中掩盖每个可能的异常,并在代码中添加 no 自我文档,以及 可能会被掩盖。
如果SavePerson
无法拯救这个人怎么办? :(一切都会愉快地继续下去(好吧,除了没有得救的弗雷德先生......他可能会心烦意乱。 )
带有显式“null-check”的代码不会受到此问题的困扰,和会添加自我文档。 明显预计null
案例(无论该推理是否有效是另一个故事)。如果缩进级别数是问题,请考虑使用合同不接受null
值的内部方法。
快乐的编码。
答案 4 :(得分:1)
对普通控制流使用异常是一种非常糟糕的做法。由于堆栈展开,try-catch变体可能比空检查慢1000倍。