为什么在c#中使用finally ?

无论finally块中的内容是什么,它总是被执行(几乎),那么将代码封闭到它或不封闭它之间有什么区别呢?

86484 次浏览

因为即使在catch块中不处理异常,finally也会被执行。

假设您需要将光标设置回默认指针,而不是等待(沙漏)光标。如果在设置光标之前抛出异常,并且没有完全崩溃应用程序,则可能会留下一个令人困惑的光标。

finally,如:

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

是在try..catch块之后执行代码的保证机会,不管你的try块是否抛出异常。

这使得它非常适合于释放资源、db连接、文件句柄等。

最后一个方块对于清理try块中分配的任何资源以及运行任何必须执行的代码(即使存在异常)是有价值的。无论try块如何退出,控件总是传递给finally块。

无论是否存在异常,finally块中的代码都将被执行。当涉及到某些需要经常运行的内务功能(如关闭连接)时,这非常方便。

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

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

什么时候你可以这样做:

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


alwaysDoThis();

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

啊…我想我明白你的意思了!我花了一点时间……你可能想知道“为什么把它放在finally块中,而不是放在finally块之后,并且完全在try-catch-finally之外”。

例如,这可能是因为抛出错误时您正在停止执行,但您仍然希望清理资源,例如打开的文件、数据库连接等。

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

例如:

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

使用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).
}

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

任何时候你使用非托管代码请求,如流读取器,db请求等;你想要捕获异常,然后使用try catch finally并在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();
}

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

最后,语句甚至可以在返回后执行。

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
}

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

[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]
< p >与例外 1 > 2 > 3 > 4 > if 3有Return语句 1 > 2 > 3 > 4

< p >没有例外 1 > 2 > 4 > 如果2有一个返回语句 1 > 2 > 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();声明将永远不会被执行 因此,与reader相关的资源从未被释放

  • 为了解决上面的问题,我们使用最后
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();
}
}

快乐编码:)

<强>注意: “@”用于创建逐字字符串,以避免出现“无法识别的转义序列”错误。 符号@意味着从字面上读取该字符串,而不以其他方式解释控制字符

正如文档中提到的:

catch和finally的一个常见用法是在try块中获取和使用资源,在catch块中处理异常情况,并在finally块中释放资源。

也值得一读,它声明:

一旦找到匹配的catch子句,系统就准备将控制转移到catch子句的第一个语句。在catch子句开始执行之前,系统首先按顺序执行所有与try语句关联的finally子句,这些语句的嵌套比捕获异常的语句嵌套多。

因此,即使前面的catch子句有return语句,驻留在finally子句中的代码也将被执行。