为什么最终在C#中使用?


189

最终块中的任何内容总是(几乎)执行,那么将代码封装到其中还是不封闭到底有什么区别?


3
保持不公开状态是什么意思?
拉梅什(Ramesh)

5
那“(几乎)”是什么意思?
Beska

49
如果在机器执行try子句时拔出电源线,将不会调用finally子句。
Dour High Arch

5
大声笑,是的,这是真的,但是您不能为此编写代码吗?
Ed S.

2
@Ed:使用交易。您的try子句必须进行某种临时或内存更改,这些更改可以持久存储在finally子句中的单个原子更改中。这很少容易实现,可能需要特殊的硬件。
Dour High Arch

Answers:


405

无论是否存在异常,finally块中的代码都将被执行。当涉及某些家政功能时,这非常方便,您需要始终像关闭连接一样运行。

现在,我您的问题是为什么您应该这样做:

try
{
    doSomething();
}
catch
{
    catchSomething();
}
finally
{
    alwaysDoThis();
}

当您可以这样做时:

try
{
    doSomething();
}
catch
{
    catchSomething();
}

alwaysDoThis();

答案是很多时候,catch语句中的代码要么抛出异常,要么脱离当前函数。对于后面的代码,“ alwaysDoThis();” 如果catch语句中的代码发出返回或引发新异常,则调用将不会执行。


3
嗯 与我说的话非常相似,但更清楚更准确。确定+1。
Beska

46
这也适用于try {}块中的“返回”。
卢卡斯2009年

4
实际上,即使没有catch {}块,它也适用(只要尝试/最后,让异常冒出来)
卢卡斯,2009年

比我的更好,我在工作,不想花十分钟详细回答。+1
马特·布里格斯

2
是的,这正是我的初衷:D现在我明白了。
罗德里戈

62

已经指出了使用try-finally的大多数优点,但是我想我应该添加这一点:

try
{
    // Code here that might throw an exception...

    if (arbitraryCondition)
    {
        return true;
    }

    // Code here that might throw an exception...
}
finally
{
    // Code here gets executed regardless of whether "return true;" was called within the try block (i.e. regardless of the value of arbitraryCondition).
}

这种行为使它在各种情况下都非常有用,特别是当您需要执行清理(处置资源)时,尽管 在这种情况下使用using块通常会更好。


2
这实际上是我最终使用的唯一原因
Christopher Townsend

12

每当您使用非托管代码请求(例如流读取器,数据库请求等)时;并且您想捕获异常,然后使用try catch finally并最终关闭流,数据读取器等。如果您不这样做,则错误不会导致连接没有关闭,这对于db请求确实很不好

 SqlConnection myConn = new SqlConnection("Connectionstring");
        try
        {
            myConn.Open();
            //make na DB Request                
        }
        catch (Exception DBException)
        {
            //do somehting with exception
        }
        finally
        {
           myConn.Close();
           myConn.Dispose();
        }

如果您不想捕获错误,请使用

 using (SqlConnection myConn = new SqlConnection("Connectionstring"))
        {
            myConn.Open();
            //make na DB Request
            myConn.Close();
        }

如果有错误,连接对象将被自动处理,但是您不会捕获该错误


2
Dispose()还将关闭()连接,无需同时调用两者。Close()不会Dipose(),您可以重新打开连接。
卢卡斯2009年

很好,谢谢您提到使用。否则,我将不得不回答。
丹·罗森斯塔克


7

即使返回,finally语句也可以执行。

private int myfun()
{
    int a = 100; //any number
    int b = 0;
    try
    {
        a = (5 / b);
        return a;
    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
        return a;
    }

 //   Response.Write("Statement after return before finally");  -->this will give error "Syntax error, 'try' expected"
    finally
    {
      Response.Write("Statement after return in finally"); // --> This will execute , even after having return code above
    } 

    Response.Write("Statement after return after finally");  // -->Unreachable code
}

7

finally,如:

try {
  // do something risky
} catch (Exception ex) {
  // handle an exception
} finally {
  // do any required cleanup
}

是您执行后保证执行代码的机会 try..catch无论您的try块是否引发异常,这都是块。

这使其非常适合发布资源,数据库连接,文件句柄等。


3
所有这些示例通常都可以通过using块更好地使用,但这并不会真的减损您的回答。
Joel Coehoorn

4

我将解释在文件读取器异常示例中finally的使用

  • 最终没有使用
try{

  StreamReader strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
  Console.WriteLine(strReader.ReadeToEnd());
  StreamReader.Close();
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}

在上面的示例中,如果缺少名为Data.txt文件,则将引发并处理异常,但将永远不会执行被调用的语句因此,与阅读器相关的资源从未发布。StreamReader.Close();

  • 为了解决上述问题,我们最后使用
StreamReader strReader = null;
try{
    strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
    Console.WriteLine(strReader.ReadeToEnd());
}
catch (Exception ex){
    Console.WriteLine(ex.Message);
}
finally{
    if (strReader != null){
        StreamReader.Close();
    }
}

快乐编码:)

注意: “ @”用于创建逐字字符串,以避免出现“无法识别的转义序列”错误。@符号表示从字面上读取该字符串,否则不解释控制字符。


2

假设您需要将光标重新设置为默认指针,而不是等待(沙漏)光标。如果在设置游标之前引发了异常,并且没有使应用程序彻底崩溃,则可能会留下混乱的游标。


2

有时,您不想处理异常(没有catch块),但是您希望执行一些清理代码。

例如:

try
{
    // exception (or not)
}
finally
{
    // clean up always
}

如果未捕获到异常,则finally块的执行取决于操作系统是否选择触发异常展开操作。
Vikas Verma 2014年

2

finally块对于清理try块中分配的所有资源以及运行即使有异常也必须执行的任何代码非常有用。无论try块如何退出,控制总是传递给finally块。


1

啊...我想我明白你在说什么!花了我几秒钟的时间...您想知道“为什么将其放置在finally块中而不是在finally块之后并完全放在try-catch-finally外”。

例如,这可能是因为如果引发错误,您将暂停执行,但是您仍想清理资源,例如打开的文件,数据库连接等。


1

Final块的控制流在Try或Catch块之后。

[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]

如果3具有返回语句1> 2> 3> 4,则异常1> 2> 3> 4> 5

无异常1> 2> 4> 5,如果2具有返回语句1> 2> 4


0

文档中所述:

catch和final一起使用的常见用法是在try块中获取和使用资源,在catch块中处理特殊情况,然后在finally块中释放资源。

还值得阅读this,其中指出:

找到匹配的catch子句后,系统准备将控制权转移到catch子句的第一条语句。在开始执行catch子句之前,系统首先按顺序执行与try语句相关联的所有finally子句,其嵌套程度要比捕获异常的子句更多。

因此很明显,finally即使在先catch子句中有一条return语句,驻留在子句中的代码也将被执行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.