关于c#:在.NET中使用try-catch进行流量控制是“不好的”吗?

Is it “bad” to use try-catch for flow control in .NET?

我刚在一个项目中发现:

1
2
3
4
5
6
7
8
try
{
    myLabel.Text = school.SchoolName;
}
catch
{
    myPanel.Visible = false;
}

我想和开发人员谈谈,而不是写这篇文章,我说引发空异常(因为理论上,school可能是空的,而不是myLabel实际上会使计算机发出三次哔哔哔声,并休眠两秒钟。不过,我想知道我是否记错了这条规则。显然,这不是try/catch的预期用途,但这是因为它违背了意图而造成的,还是因为性能考虑而造成的?我觉得这很糟糕,但我想说的不仅仅是"那真的很糟糕"。


您不应该简单地为控制流使用异常,因为它的设计不好。这没有道理。例外情况适用于例外情况,而非正常流量。在这种情况下,性能可能不是问题,因为对于大多数现代硬件上的现代应用程序,您可以整天抛出异常,用户不会注意到性能受到影响。但是,如果这是一个高性能的应用程序,处理大量的数据或者做大量的工作,那么性能就是一个问题。


在我看来,这是很糟糕的,因为它可以通过一个if语句更清楚地表达出来:

1
2
3
4
5
6
if (school != null) {
    myLabel.Text = school.SchoolName;
}
else {
    myPanel.Visible = false;
}

这当然可以避免不必要地使用异常处理,并使代码的含义非常明显。


我认为这很糟糕,因为它是针对一个异常进行编码的,而且它还将继承不必要的开销。只有以特定方式处理异常时,才应捕获异常。

对于您无法预测的异常情况,应特别捕获异常,在这种情况下,只需简单检查一下学校是否可以为空,事实上,学校可能是空的(因为标签什么都没有设置)。如果学校是空的,并且不应该超过它应该抛出自己的argumentNullException。


异常确实会导致运行时开销,但在这里可能可以忽略不计。在调试器中运行会有所不同,但是构建的二进制文件应该以几乎相同的速度运行。

告诉你的开发者,任何黑猩猩都能制造出机器可以阅读的代码。好的代码是为人类而不是机器编写的。如果一个空异常是您唯一担心的事情,那么它可能是用户代码中的一个bug——任何人都不应该试图以这种方式将空分配给任何东西。使用Assert()语句。


引发异常确实会对性能产生负面影响,请参阅http://msdn.microsoft.com/en-us/library/ms229009(vs.80).aspx


你说得对,这很糟糕。这是不好的,因为它违背了意图,也因为它损害了性能。

我意识到有空间使用不同的编程风格,但就我个人而言,我认为即使这样做是可行的,而且我可以看到代码正在尝试做什么,这也会损害可读性和代码清晰性,使维护程序员更难遵循这一点。这里的if语句更合适。


在"为什么不使用异常作为常规控制流"上查看此文章?


我从不喜欢在流控制中使用异常。异常是昂贵的,并且很难确定程序的实际流,异常被抛出到代码中的其他地方。对我来说,这就像用goto。这并不意味着您应该避免异常,而是一个异常应该只是这个,一个异常应该是程序中正常发生的异常。

我认为代码中更糟糕的部分是,它甚至没有做任何异常的事情。没有日志记录,甚至没有解释为什么抛出异常。


我同意这里的每一个人——这是一个可怕的想法。

在Java中有几个案例(我认为它们现在大部分已经消失了,但是在外部库中可能还有一些),在那里您需要捕获某些"非例外"情况下的异常。

一般来说,在编写库代码时(实际上是任何类),避免对任何可能避免的事情使用异常。如果可能没有设置名称字段,这会导致write()方法中出现异常,请确保添加一个isvalid()方法,这样实际上就不必在write周围捕获异常,就可以知道存在问题。

(坏的Java代码补充):这种"好"的编程风格实际上消除了Java中检查异常的任何需要,而Java中的异常检查则是一个缺陷。