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

时间:2009-02-13 21:36:33

标签: c# exception-handling

无论内部是什么,最终块(几乎)总是被执行,那么将代码封装到其中或将其保持未封闭之间的区别是什么?

15 个答案:

答案 0 :(得分:374)

无论是否存在异常,finally块中的代码都将被执行。这对于某些内务处理功能非常方便,您需要始终像关闭连接那样运行。

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

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

当你能做到这一点时:

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

alwaysDoThis();

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

答案 1 :(得分:57)

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

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

答案 2 :(得分:11)

任何时候使用非托管代码请求,如流读取器,数据库请求等;并且你想捕获异常然后使用try catch finally并在最后关闭流,数据读取器等,如果你没有错误连接没有关闭,这对db请求来说真的很糟糕< / p>

 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();
        }

如果出现错误,连接对象将自动处理,但您不会捕获错误

答案 3 :(得分:10)

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

答案 4 :(得分:7)

finally,如:

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

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

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

答案 5 :(得分:7)

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

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
}

答案 6 :(得分:3)

通过使用finally块,您可以清除try块中分配的所有资源,即使try块中发生异常,您也可以运行代码。通常,当控件离开try语句时,finally块的语句会运行。控制权的转移可能是由于正常执行,执行break, continue, goto, or return语句或从try语句传播异常而发生的。

在处理的异常中,保证运行关联的finally块。但是,如果未处理异常,则finally块的执行取决于如何触发异常展开操作。反过来,这取决于您的计算机的设置方式。有关详细信息,请参阅Unhandled Exception Processing in the CLR

通常,当未处理的异常结束应用程序时,无论finally块是否运行都不重要。但是,如果在finally块中的语句即使在这种情况下也必须运行,一种解决方案是在catch语句中添加try-finally块。或者,您可以捕获可能在调用堆栈上方try语句的try-finally块中抛出的异常。也就是说,您可以在调用包含try-finally语句的方法的方法中,或在调用该方法的方法中,或在调用堆栈的任何方法中捕获异常。如果未捕获到异常,则finally块的执行取决于操作系统是否选择触发异常展开操作。

public class ThrowTestA
{
    static void Main()
    {
        int i = 123;
        string s = "Some string";
        object obj = s;

        try
        {
            // Invalid conversion; obj contains a string, not a numeric type.
            i = (int)obj;

            // The following statement is not run.
            Console.WriteLine("WriteLine at the end of the try block.");
        }
        finally
        {
            // To run the program in Visual Studio, type CTRL+F5. Then  
            // click Cancel in the error dialog.
            Console.WriteLine("\nExecution of the finally block after an unhandled\n" +
                "error depends on how the exception unwind operation is triggered.");
            Console.WriteLine("i = {0}", i);
        }
    }
    // Output: 
    // Unhandled Exception: System.InvalidCastException: Specified cast is not valid. 
    // 
    // Execution of the finally block after an unhandled 
    // error depends on how the exception unwind operation is triggered. 
    // i = 123
}

在下面的示例中,TryCast方法的异常捕获在调用堆栈更远的方法中。 C#

public class ThrowTestB
{
    static void Main()
    {
        try
        {
            // TryCast produces an unhandled exception.
            TryCast();
        }
        catch (Exception ex)
        {
            // Catch the exception that is unhandled in TryCast.
            Console.WriteLine
                ("Catching the {0} exception triggers the finally block.",
                ex.GetType());

            // Restore the original unhandled exception. You might not 
            // know what exception to expect, or how to handle it, so pass  
            // it on. 
            throw;
        }
    }

    public static void TryCast()
    {
        int i = 123;
        string s = "Some string";
        object obj = s;

        try
        {
            // Invalid conversion; obj contains a string, not a numeric type.
            i = (int)obj;

            // The following statement is not run.
            Console.WriteLine("WriteLine at the end of the try block.");
        }
        finally
        {
            // Report that the finally block is run, and show that the value of 
            // i has not been changed.
            Console.WriteLine("\nIn the finally block in TryCast, i = {0}.\n", i);
        }
    }
    // Output: 
    // In the finally block in TryCast, i = 123. 

    // Catching the System.InvalidCastException exception triggers the finally block. 

    // Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
}

答案 7 :(得分:3)

我将用文件阅读器异常示例

解释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();
    }
}

快乐编码:)

注意: &#34; @&#34;用于创建逐字字符串,以避免&#34;无法识别的转义序列&#34;的错误。 @符号表示按字面意思读取该字符串,否则不解释控制字符。

答案 8 :(得分:2)

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

答案 9 :(得分:2)

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

答案 10 :(得分:2)

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

例如:

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

答案 11 :(得分:1)

啊......我想我明白你在说什么!花了我一分钟......你想知道“为什么把它放在finally块中而不是在finally块之后,完全在try-catch-finally之外”。

例如,可能是因为如果抛出错误就停止执行,但是仍然想要清理资源,例如打开文件,数据库连接等。

答案 12 :(得分:1)

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

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

有异常 1> 2&gt; 3> 4>五 如果3有一个Return语句 1> 2&gt; 3> 4

没有例外 1> 2&gt; 4>五 如果2有一个return语句 1> 2&gt; 4

答案 13 :(得分:0)

最后阻止

如果在退出Try结构之前必须运行一个或多个语句,请使用Finally块。 Finally块对于运行任何必须执行的代码非常有用,即使存在异常也是如此。无论Finally ... Try块如何退出,控制都会传递到Catch块。控制权在传递出Finally ... Try结构之前传递到Catch块。即使在Try结构内的任何位置发生异常,也是如此。即使您的代码在FinallyReturn块中遇到Try语句,Catch块中的代码也会运行。

将执行显式转移到Finally块无效。

Finally块传输执行无效,除非是例外。

答案 14 :(得分:0)

documentation中所述:

  

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

也值得一读this,其中指出:

  

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

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