考虑以下C#代码结构(S0-S3是任意代码块的占位符):
try
{
S0;
}
catch (Exception ex)
{
S1;
}
finally
{
S2;
}
S3;
如果S1在catch
处理程序中抛出异常,finally
内的S2仍将执行(但S3不会执行)。
假设S1不能抛出,那么在finally
块内部有S2是否有任何意义,而不是在try / catch / finally之外,就在S3之前?
try
{
// Do something that might throw
}
catch (Exception ex)
{
// Save the exception to re-throw later
// NB: This statement cannot throw an exception!
this.cachedException = ex;
}
finally
{
S2;
}
S3;
有finally
阻止是否有任何意义?以下代码是否不等同(严格假设catch
块内的内容不能抛出):
try
{
// Do something that might throw
}
catch (Exception ex)
{
// Save the exception to re-throw later
// NB: This statement cannot throw an exception!
this.cachedException = ex;
}
// No finally block needed (?)
S2;
S3;
更新:如果接受上述两个代码块是等效的(根据所述假设),那么考虑到答案中代码清晰度的反馈,它是否可取(并且等效)在finally
块内组合S2和S3?
try
{
// Do something that might throw
}
catch (Exception ex)
{
// Save the exception to re-throw later
// NB: This statement cannot throw an exception!
this.cachedException = ex;
}
finally
{
S2; // Put S2 and S3 together inside the `finally` block to guard against
S3; // future changes in the `catch` filter, or handling code.
}
答案 0 :(得分:12)
考虑到资源耗尽情况(即内存不足),S1不能抛出的假设是脆弱的。即使有必要(一个很大的if),对代码的微小更改也会引入异常。
由于S2通常关注清理和释放有价值的资源,因此将其置于finally块中可以清楚地传达意图。在可能的情况下,将这些代码放在资源拥有对象的Dispose()方法中,并用using子句替换try / finally子句,可以更好地传达意图(对于C#更具惯用性)。
每当您可以用两种或更多种方式编写内容时,请使用最清晰且最稳定的更改方式。
重新提出问题:如果涉及清理,S3应该放在finally中。如果它预先假定try块的成功,它应该放在finally块之后。如果您的catch语句没有重新抛出,我个人会将其解释为您已成功并可以继续正常操作。然而,整个'保存例外以后重新抛出'的事情让我感到困惑。一般来说,我建议不要在方法之外存储重新抛出的异常。这很不寻常,对我来说似乎很困惑。代码包含的意外越少,维护就越容易(包括你自己,三个月后)。
答案 1 :(得分:10)
你可能没有预料到S1抛出的一种情况:如果线程被中断,异常将自动在catch块的末尾重新抛出。
正如Pontus所说,finally
块表示无论发生什么,都应该始终运行此代码。这比捕捉一切然后继续更清楚。
答案 2 :(得分:3)
finally块用于进行资源清理,无论是否发生异常,最后都会调用block,因此它是进行清理工作的理想场所。
答案 3 :(得分:3)
请注意,即使try或catch块包含return语句,也会执行finally子句。
答案 4 :(得分:3)
我认为这类似于在语句内容中添加括号。
虽然你可以争辩说
if (x) y;
不会失败,是什么意思说一些经验不足的程序员以后不会出现并将其编辑为
if (x) y; z;
可能是这样的情况,你的代码不需要finally块,但是如果catch块中的代码发生变化,最好留下它。
if (x)
{
y;
}
总是为我赢。
答案 5 :(得分:2)
在您的特定情况下,没有区别......
但是如果你没有捕获Exception,而是Exception的某个特定子类,那么就会有所不同。在查看try-catch-finally块时,这可能是正常的模式。
答案 6 :(得分:1)
您可以确保您的代码今天不会抛出异常,但是当您在6个月内回复它时又如何呢?或者其他人必须做出改变?
使用finally
块是一种公认的模式,对任何程序员都有意义,如果您的代码执行特殊和不同的操作,将绊倒您或其他人。
答案 7 :(得分:1)
在第二种情况下,控件只会在吞下catch块中的任何异常时才会到达S2! Try-Catch不应该在这里使用,而应该小心使用。
例如:
try
{
// Do something that might throw
}
catch (Exception ex)
{
// Save the exception to re-throw later
// NB: This statement cannot throw an exception!
// this.cachedException = ex;
// Must swallow any exception here to let control go further!
// If you're not sure enough [which you and me both are not likely to be] - use finally to execute S2 in any condition
}
// No finally block needed (?)
S2;
S3;
答案 8 :(得分:1)
为了保证在发生异常时清理资源,请使用try / finally块。关闭finally子句中的资源。使用try / finally块可确保即使发生异常也会处置资源....有关详细信息,请检查http://itpian.com/Coding/5143-Need-for-Finally-block.aspx
答案 9 :(得分:0)
不,你不必使用它。在这种情况下不需要它。它是您的选择,取决于您可能/可能不会使用的资源。如果您需要清理可能拥有的任何资源,那么finally块是最佳选择。