C#中的finally块是否必须?

8

两个条件之间有什么区别?每次运行method1或method2时,都需要运行一个必需的代码块。在我看来,这两种方法是相同的。

// example method1
void Method1(void)
{
    try
    {
        // do something
    }
    catch (Exception ex)
    {
        // do something
    }
    finally
    {
        // do something whenever method1 runs
    }
}

// example method2
void Method2(void)
{
    try
    {
        // do something
    }
    catch (Exception ex)
    {
        // do something
    }

    // do something whenever method2 runs
}

最后的代码块对我来说似乎是不必要的。


1
你需要具体说明“做某事”的内容,才能让这成为一个问题。 - H H
请阅读以下内容以获取更多信息。最后是可选的,您可以在所有处理完成后释放资源。http://msdn.microsoft.com/en-us/library/fk6t46tz(v=vs.71).aspx - Kaf
不,它们不是一样的。finally块确保其中包含的代码运行,无论发生什么。 - Cody Gray
3
不要去抓你无法控制的东西。 - Jodrell
VB.NET的问题,但基本相同:https://dev59.com/vHM_5IYBdhLWcg3w8IHR - nawfal
显示剩余2条评论
7个回答

17
在您的第一个示例中,您可以重新抛出异常并且 finally 中的代码仍将运行。这在第二个示例中是不可能的。
如果您选择不重新抛出异常,则确实几乎没有区别。但是,这被认为是不好的形式——很少需要消耗您无法明确处理的异常。
它是一个关键字,可帮助您处理代码执行流程。当您抛出异常时,代码的执行流程会受到影响(就像使用 return 一样),finally 关键字允许您表达当发生异常(或从 try 中返回)时,您仍希望执行某些操作。
玩笑地回答问题,当您需要它时,它是必须的,否则不需要。
进一步阅读
为了安全起见,在尝试开始使用此关键字之前,请阅读其文档。

http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx

并且一般情况下,异常处理关键字:

http://msdn.microsoft.com/en-us/library/s7fekhdy.aspx


Examples

捕获异常以进行处理,然后重新抛出异常。使用finally调用任何清理代码:
try
{
    OpenConnectionToDatabase();
    // something likely to fail
}
catch (Exception ex)
{
    Log(ex);
    throw;  
    // throw ex; // also works but behaves differently
}
// Not specifying an exception parameter also works, but you don't get exception details.
//catch (Exception)
//{
//    Log("Something went wrong);
//    throw;
//}
finally
{
    CloseConnectionToDatabase();
}

不要注册任何有关捕获异常的兴趣,而是使用 finally 来整理代码:
try
{
    OpenConnectionToDatabase();
    // something likely to fail
}
finally
{
    CloseConnectionToDatabase();
}

在你的try中返回结果,因为它看起来格式良好,但仍然使用finally清理代码:

try
{
    OpenConnectionToDatabase();
    return 42;
}
finally
{
    CloseConnectionToDatabase();
}

嗯,有点是有点不是。在我的基类中,我有很多捕获(重新抛出)的情况——它们调用一个日志接口将异常写入应用程序日志。即使已经在更高层次上处理了,我仍然想随时知道诸如数据库异常之类的信息。 - TomTom
1
@TomTom,它们不是被消耗的,而是被观察并传播。我所说的消耗是指吞咽后永远不会再见到它们。 - Adam Houldsworth
@AdamHouldsworth他很清楚finally的作用,但不明白为什么需要它。我认为这会对他有所帮助,比“阅读规范”更有帮助。 - AnthonyBlake
@AdamHouldsworth,很抱歉我建议你如何改进你的回答。我只是想帮助人们。我看到你删除了那条评论。很抱歉我没有想到会触及你的神经。 - AnthonyBlake
让我们在聊天中继续这个讨论 - AnthonyBlake

3

正如您所知,finally块中编写的代码总是会运行。请看下面写的几点,它们将消除您所有的疑惑。

  1. finally用于资源管理。主要用于释放资源。无论是否有异常发生,它都会运行。
    1. 我们知道catch用于处理异常,但有时它无法处理外部异常然后使用finally块来处理该异常以执行操作。

2

finally块中的代码将在try-catch之后运行,它非常有用于清理工作。

try
{
    // open resources
}
catch (Exception ex)
{
    // something bad happened
}
finally
{
    // close resources that are still opened
}

1

你并不是非得使用 finally 代码块,但是使用它可以确保其中的代码一定会执行(除非在 finally 块中抛出了异常!)。

考虑以下情况:

void Method2(void) 
{ 
    try 
    { 
        // do something 
    } 
    catch (Exception ex) 
    { 
        // do something 
        throw;
    } 

    // do something whenever method2 runs 
} 

如果抛出异常,try/catch后面的代码将不会执行。此外,如果catch块内的代码存在导致异常的错误(例如日志记录引发了意外异常),本应在finally中运行的代码将不会运行,留下未完成的清理工作。

另外,return语句将导致该代码不被执行,而finally仍将被执行(同样,在这里可以看到,catch也可以被跳过,允许任何异常向上传播 - 在执行finally之后):

void Method2(void) 
{ 
    try 
    {  
        // do something
        return
    } 
    finally
    {     
        // do something whenever method2 runs 
    }
} 

无论何时,当您有必须在方法结束时运行的清理代码时,请使用finally(或者如果您的对象实现了IDisposable,请使用using语句)。

1

这取决于您从tryreturn的方式,其行为会有很大不同。此外,即使catch抛出异常(或重新抛出原始异常),finally也将运行,否则将不会发生这种情况。

所以:它不是必需的,但行为会有所不同。因此,如果您希望代码执行,将其放入finally中。

在许多方面,try/finallytry/catchtry/catch/finally更常见。


0

finally 块确保其中的任何代码始终得到执行,因此如果您在 try 块内有一个返回语句或在 catch 块内重新抛出异常,则 finally 块内的代码将始终执行。

如果您需要确保发生某些事情(例如释放资源等),则必须使用它。


0

最大的区别在于try...catch会吞掉异常,隐藏了错误发生的事实。而try...finally将运行您的清理代码,然后异常将继续传递,由知道如何处理它的东西来处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接