C# 为什么 try {...} finally {...} 好;尝试 {...} catch{} 不好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/128818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is try {...} finally {...} good; try {...} catch{} bad?
提问by mbeckish
I have seen people say that it is bad form to use catch with no arguments, especially if that catch doesn't do anything:
我见过有人说使用不带参数的 catch 是不好的形式,尤其是当 catch 不做任何事情时:
StreamReader reader=new StreamReader("myfile.txt");
try
{
int i = 5 / 0;
}
catch // No args, so it will catch any exception
{}
reader.Close();
However, this is considered good form:
但是,这被认为是好的形式:
StreamReader reader=new StreamReader("myfile.txt");
try
{
int i = 5 / 0;
}
finally // Will execute despite any exception
{
reader.Close();
}
As far as I can tell, the only difference between putting cleanup code in a finally block and putting cleanup code after the try..catch blocks is if you have return statements in your try block (in that case, the cleanup code in finally will run, but code after the try..catch will not).
据我所知,将清理代码放在 finally 块中和将清理代码放在 try..catch 块之后的唯一区别是,如果您的 try 块中有 return 语句(在这种情况下,finally 中的清理代码将运行,但 try..catch 之后的代码不会)。
Otherwise, what's so special about finally?
否则,finally 有什么特别之处呢?
采纳答案by Khoth
The big difference is that try...catch
will swallow the exception, hiding the fact that an error occurred. try..finally
will run your cleanup code and then the exception will keep going, to be handled by something that knows what to do with it.
最大的区别是try...catch
会吞下异常,隐藏发生错误的事实。try..finally
将运行您的清理代码,然后异常将继续存在,由知道如何处理它的东西处理。
回答by Adam Wright
"Finally" is a statement of "Something you must always do to make sure program state is sane". As such, it's always good form to have one, if there's any possibility that exceptions may throw off the program state. The compiler also goes to great lengths to ensure that your Finally code is run.
“最后”是“您必须始终做的事情以确保程序状态正常”的声明。因此,如果异常可能会抛出程序状态,那么拥有一个总是好的形式。编译器还竭尽全力确保您的Finally 代码运行。
"Catch" is a statement of "I can recover from this exception". You should only recover from exceptions you really can correct - catch without arguments says "Hey, I can recover from anything!", which is nearly always untrue.
“Catch”是“我可以从这个异常中恢复”的声明。你应该只从你真正可以纠正的异常中恢复 - 没有参数的 catch 说“嘿,我可以从任何事情中恢复!”,这几乎总是不真实的。
Ifit were possible to recover from every exception, then it would really be a semantic quibble, about what you're declaring your intent to be. However, it's not, and almost certainly frames above yours will be better equipped to handle certain exceptions. As such, use finally, get your cleanup code run for free, but still let more knowledgeable handlers deal with the issue.
如果有可能从每个异常中恢复,那么这真的是一个语义上的狡辩,关于你声明你的意图是什么。然而,事实并非如此,几乎可以肯定,高于您的框架将能够更好地处理某些异常。因此,使用 finally,让您的清理代码免费运行,但仍然让更多知识渊博的处理程序处理该问题。
回答by Mark Cidade
If you don't know what exception type to catch or what to do with it, there's no point in having a catch statement. You should just leave it for a higher-up caller that may have more information about the situation to know what to do.
如果您不知道要捕获什么异常类型或如何处理它,那么使用 catch 语句就毫无意义。你应该把它留给更高层的呼叫者,他可能有更多关于这种情况的信息,知道该怎么做。
You should still have a finally statement in there in case there is an exception, so that you can clean up resources before that exception is thrown to the caller.
如果出现异常,您仍然应该在那里有一个 finally 语句,以便您可以在将该异常抛出给调用者之前清理资源。
回答by Ryan
From a readability perspective, it's more explicitly telling future code-readers "this stuff in here is important, it needs to be done no matter what happens." This is good.
从可读性的角度来看,它更明确地告诉未来的代码阅读器“这里的东西很重要,无论发生什么都需要完成。” 这很好。
Also, empty catch statements tend to have a certain "smell" to them. They might be a sign that developers aren't thinking through the various exceptions that can occur and how to handle them.
此外,空的 catch 语句往往对它们有一定的“气味”。它们可能表明开发人员没有考虑可能发生的各种异常以及如何处理它们。
回答by Kibbee
With finally, you can clean up resources, even if your catch statement throws the exception up to the calling program. With your example containing the empty catch statement, there is little difference. However, if in your catch, you do some processing and throw the error, or even just don't even have a catch at all, the finally will still get run.
使用 finally,您可以清理资源,即使您的 catch 语句向调用程序抛出异常。对于包含空 catch 语句的示例,几乎没有区别。但是,如果在您的捕获中,您进行了一些处理并抛出错误,或者甚至根本没有捕获,则 finally 仍然会运行。
回答by chakrit
Because when that one single line throws an exception, you wouldn't know it.
因为当那一行抛出异常时,你不会知道。
With the first block of code, the exception will simply be absorbed, the program will continue to execute even when the state of the program might be wrong.
对于第一个代码块,异常将被简单地吸收,即使程序状态可能出错,程序也会继续执行。
With the second block, the exception will be thrownand bubbles up butthe reader.Close()
is still guaranteed to run.
与第二块,异常会被抛出,并冒泡,但在reader.Close()
仍然保证运行。
If an exception is not expected, then don't put a try..catch block just so, it'll be hard to debug later when the program went into a bad state and you don't have an idea why.
如果异常不是预期的,那么不要就这样放置 try..catch 块,以后当程序进入错误状态并且您不知道原因时很难调试。
回答by Guy Starbuck
Finally is optional -- there's no reason to have a "Finally" block if there are no resources to clean up.
最后是可选的——如果没有要清理的资源,就没有理由使用“最后”块。
回答by lotsoffreetime
Amongst probably many reasons, exceptions are very slow to execute. You can easily cripple your execution times if this happens a lot.
在可能有很多原因中,异常执行起来很慢。如果这种情况经常发生,您可以轻松缩短执行时间。
回答by SpoiledTechie.com
Taken from: here
取自:这里
Raising and catching exceptions should not routinely occur as part of the successful execution of a method. When developing class libraries, client code must be given the opportunity to test for an error condition before undertaking an operation that can result in an exception being raised. For example, System.IO.FileStream provides a CanRead property that can be checked prior to calling the Read method, preventing a potential exception being raised, as illustrated in the following code snippet:
引发和捕获异常不应作为方法成功执行的一部分而经常发生。在开发类库时,在执行可能导致引发异常的操作之前,客户端代码必须有机会测试错误条件。例如,System.IO.FileStream 提供了一个 CanRead 属性,可以在调用 Read 方法之前检查该属性,以防止引发潜在的异常,如以下代码片段所示:
Dim str As Stream = GetStream() If (str.CanRead) Then 'code to read stream End If
Dim str As Stream = GetStream() If (str.CanRead) Then '读取流的代码 End If
The decision of whether to check the state of an object prior to invoking a particular method that may raise an exception depends on the expected state of the object. If a FileStream object is created using a file path that should exist and a constructor that should return a file in read mode, checking the CanRead property is not necessary; the inability to read the FileStream would be a violation of the expected behavior of the method calls made, and an exception should be raised. In contrast, if a method is documented as returning a FileStream reference that may or may not be readable, checking the CanRead property before attempting to read data is advisable.
在调用可能引发异常的特定方法之前是否检查对象状态的决定取决于对象的预期状态。如果 FileStream 对象是使用应该存在的文件路径和应该以读取模式返回文件的构造函数创建的,则不需要检查 CanRead 属性;无法读取 FileStream 将违反所进行的方法调用的预期行为,并且应该引发异常。相反,如果方法被记录为返回可能可读也可能不可读的 FileStream 引用,则建议在尝试读取数据之前检查 CanRead 属性。
To illustrate the performance impact that using a "run until exception" coding technique can cause, the performance of a cast, which throws an InvalidCastException if the cast fails, is compared to the C# as operator, which returns nulls if a cast fails. The performance of the two techniques is identical for the case where the cast is valid (see Test 8.05), but for the case where the cast is invalid, and using a cast causes an exception, using a cast is 600 times slower than using the as operator (see Test 8.06). The high-performance impact of the exception-throwing technique includes the cost of allocating, throwing, and catching the exception and the cost of subsequent garbage collection of the exception object, which means the instantaneous impact of throwing an exception is not this high. As more exceptions are thrown, frequent garbage collection becomes an issue, so the overall impact of the frequent use of an exception- throwing coding technique will be similar to Test 8.05.
为了说明使用“运行直到异常”编码技术可能导致的性能影响,将转换的性能(如果转换失败则抛出 InvalidCastException)与 C# as 运算符进行比较,后者在转换失败时返回空值。对于强制转换有效的情况(参见测试 8.05),这两种技术的性能是相同的,但是对于强制转换无效并且使用强制转换导致异常的情况,使用强制转换比使用强制转换慢 600 倍作为操作员(见测试 8.06)。异常抛出技术的高性能影响包括分配、抛出和捕获异常的成本以及异常对象后续垃圾收集的成本,这意味着抛出异常的瞬时影响没有那么高。随着更多的异常被抛出,
回答by David Mohundro
The problem with try/catch blocks that catch all exceptions is that your program is now in an indeterminate state if an unknown exception occurs. This goes completely against the fail fast rule - you don't want your program to continue if an exception occurs. The above try/catch would even catch OutOfMemoryExceptions, but that is definitely a state that your program will not run in.
捕获所有异常的 try/catch 块的问题在于,如果发生未知异常,您的程序现在处于不确定状态。这完全违背了快速失败规则——如果发生异常,你不希望你的程序继续。上面的 try/catch 甚至会捕获 OutOfMemoryExceptions,但这绝对是您的程序不会运行的状态。
Try/finally blocks allow you to execute clean up code while still failing fast. For most circumstances, you only want to catch all exceptions at the global level, so that you can log them, and then exit out.
Try/finally 块允许您执行清理代码,同时仍然快速失败。大多数情况下,您只想在全局级别捕获所有异常,以便您可以记录它们,然后退出。