考虑以下C#代码结构(S0-S3是任意代码块的占位符):

try
{
    S0;
}
catch (Exception ex)
{
    S1;
}
finally
{
    S2;
}

S3;

如果S1在catch处理程序内引发异常,则finally内的S2仍将执行(但S3不会)。

问题

假设S1不能抛出,那么将S2放在finally块中,而不是将其放在try/catch/final之外(就在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;

次要问题

更新:如果接受以上两个代码块等效(在陈述的假设下),那么考虑到答案中有关代码清晰度的反馈,将S2和S3合并在内部是可取的(等效)吗? finally块?
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.
}

最佳答案

考虑到资源耗尽的情况(即内存用完),S1无法抛出的假设是一个脆弱的假设。即使有保证(如果有保证的话),对代码的微小更改也会引入异常。

由于S2通常与清理和释放宝贵的资源有关,因此将其放在finally块中可以清楚地传达意图。在可能的情况下,将这样的代码放在资源拥有对象的Dispose()方法中,并用using子句替换try/finally子句,可以更好地传达意图(对于C#来说更惯用)。

只要您可以用两种或更多种不同的方式写东西,就使用最清晰,最稳定的方式来应对变化。

关于第二个问题:如果涉及到清理,则应将S3放置在finally内。如果它以try块的成功为前提,则应将其放置在finally块之后。如果您的catch语句没有被抛出,我个人将其解释为您已经成功并且可以继续进行正常操作。但是,整个“保存异常(exception)以便以后重新抛出”的事情使我感到困惑。通常,建议不要存储用于重新抛出方法的异常。这很不寻常,似乎让我感到困惑。您的代码包含的惊喜越少,维护起来就越容易(三个月后包括您自己)。

关于c# - 在C#中,finally块前面有一个包罗万象的catch块有什么用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2041654/

10-13 00:11