我见过有人说使用不带参数的catch是不好的形式,特别是如果catch没有做任何事情:
StreamReader reader=new StreamReader("myfile.txt"); try { int i = 5 / 0; } catch // No args, so it will catch any exception {} reader.Close();
但是,这被认为是好的形式:
StreamReader reader=new StreamReader("myfile.txt"); try { int i = 5 / 0; } finally // Will execute despite any exception { reader.Close(); }
据我所知,将清理代码放在finally块中并在try..catch块之后放置清理代码之间的唯一区别是,如果你的try块中有return语句(在这种情况下,最后清理代码将是运行,但try..catch之后的代码不会).
否则,最后有什么特别之处?
最大的区别在于try...catch
会吞下异常,隐藏发生错误的事实.try..finally
将运行您的清理代码然后异常将继续,由知道如何处理它的东西处理.
"最后"是一个声明"你必须做的事情,以确保程序状态是理智的".因此,如果异常可能会导致程序状态失效,那么拥有一个总是很好的形式.编译器还竭尽全力确保运行您的Finally代码.
"Catch"是"我可以从此异常中恢复"的声明.你应该只从你真正可以纠正的异常中恢复过来 - 没有争论就说:"嘿,我可以从任何东西中恢复过来!",这几乎总是不真实的.
如果有可能从每个例外中恢复,那么它实际上是一个语义狡辩,关于你宣布你的意图是什么.但是,它不是,而且几乎可以肯定,高于你的帧将更好地处理某些异常.因此,最后使用,让你的清理代码免费运行,但仍然让更多知识渊博的处理程序处理这个问题.
因为当一行引发异常时,你就不会知道它.
使用第一个代码块,将简单地吸收异常,即使程序状态可能出错,程序也将继续执行.
与第二块,异常会被抛出,并冒泡,但在reader.Close()
仍然保证运行.
如果不期望异常,那么不要放一个try..catch块,以后当程序进入错误状态并且你不知道为什么时很难调试.
最后无论如何执行.因此,如果你的try块成功,它将执行,如果你的try块失败,它将执行catch块,然后执行finally块.
此外,最好尝试使用以下构造:
using (StreamReader reader=new StreamReader("myfile.txt")) { }
由于using语句自动包装在try/finally中,因此流将自动关闭.(如果要实际捕获异常,则需要在using语句周围放置一个try/catch).
虽然以下2个代码块是等效的,但它们并不相同.
try { int i = 1/0; } catch { reader.Close(); throw; } try { int i = 1/0; } finally { reader.Close(); }
'finally'是意图揭示代码.您向编译器和其他程序员声明无论如何都需要运行此代码.
如果你有多个catch块并且你有清理代码,那么你最终需要.最后,你将在每个catch块中复制清理代码.(DRY原则)
最后块是特殊的.CLR使用finally块分别识别和处理带有finally块的代码,并且CLR竭尽全力保证finally块始终执行.这不仅仅是编译器的语法糖.
我同意这里似乎达成的共识 - 空的'catch'是坏的,因为它掩盖了try块中可能发生的任何异常.
另外,从可读性的角度来看,当我看到'try'块时,我假设会有一个相应的'catch'语句.如果您只是使用'try'以确保在'finally'块中取消分配资源,您可以考虑使用'using'语句:
using (StreamReader reader = new StreamReader('myfile.txt')) { // do stuff here } // reader.dispose() is called automatically
您可以将'using'语句与任何实现IDisposable的对象一起使用.对象的dispose()方法在块结束时自动调用.