try catch和finally块的执行顺序

时间:2010-11-16 03:42:26

标签: c#

我对try,catch和finally执行的顺序感到很困惑。

我也想知道我应该何时使用try catch块以及我应该在try catch块中放置什么,我也想知道是否有一些异常来自try block然后如果采取对应于try块的操作然后一个是先执行或最后执行(这是 总是被执行),并且在执行这两个之后确实控制返回尝试阻止或者它永远放弃它。

4 个答案:

答案 0 :(得分:6)

如果你有(注意:这是无效的C#,请参阅下面的有效示例):

try {
   // ... some code: A
} catch(...) {
   // ... exception code: B
} finally {
   // finally code: C
}

代码A将被执行。如果一切顺利(即在A执行时没有异常被抛出),它将最终进入,因此代码C将被执行。如果在执行A时抛出异常,则它将转到B,然后转到C。

例如,这是来自http://msdn.microsoft.com/en-us/library/dszsf989.aspx的有效C#代码块:

public class EHClass
{
    void ReadFile(int index)
    {
        // To run this code, substitute a valid path from your local machine
        string path = @"c:\users\public\test.txt";
        System.IO.StreamReader file = new System.IO.StreamReader(path);
        char[] buffer = new char[10];
        try
        {
            file.ReadBlock(buffer, index, buffer.Length);
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
        }
        finally
        {
            if (file != null)
            {
                file.Close();
            }
        }
        // Do something with buffer...
    }
}

使用try / catch / finally的原因是为了防止程序在某些代码中出错(上例中的A)失败。如果出现问题,您可以使用catch部分来捕获问题并执行一些有用的操作,例如通知用户,将异常记录到日志文件中,再试一次或尝试其他您认为可能有用的方法你最初尝试过的。

finally用于确保执行某些清理。例如。在A中,您可能会尝试打开文件并阅读它。如果打开成功,但读取失败,则会打开一个打开的文件。在这种情况下你想要的是关闭它,你将在finally块中执行 - 这个块总是被执行,保证文件的关闭。

请点击此处了解更多信息:

答案 1 :(得分:4)

你几乎不应该使用try / catch。

您应该只有catch例外,您可以实际纠正,并且只有在您期望它们时才会这样。否则,让调用者处理异常 - 或不。

如果使用,则首先执行任何catch子句 - 只执行其中一个。

然后,finally被“最终”执行。


在许多地方已经说明了这一点,但我会尝试。以下代码:

try
{
    // Do something here
}
catch (Exception ex)
{
    MessageBox.Show("Friendly error message");
}

不修复异常。它隐藏了异常,因此永远不会修复问题。该代码不知道抛出了哪个异常,因为它会捕获所有异常,并且它无法解决问题 - 它只是告诉用户一个礼貌的小说。

事实是上述代码应替换为以下代码:

// Do something here

这样,如果此方法的调用者知道如何修复特定问题,则调用者可以修复它们。您不会从调用者中删除该选项。

如果调用者不知道如何解决问题,那么调用者也不应该捕获异常。


以下是以合理方式使用异常的示例(来自MSDN)。它是SmtpFailedRecipientsException Class文档中示例的修改形式。

public static void RetryIfBusy(string server)
{
    MailAddress from = new MailAddress("ben@contoso.com");
    MailAddress to = new MailAddress("jane@contoso.com");
    using (
        MailMessage message = new MailMessage(from, to)
                                  {
                                      Subject = "Using the SmtpClient class.",
                                      Body =
                                          @"Using this feature, you can send an e-mail message from an application very easily."
                                  })
    {
        message.CC.Add(new MailAddress("Notifications@contoso.com"));
        using (SmtpClient client = new SmtpClient(server) {Credentials = CredentialCache.DefaultNetworkCredentials})
        {
            Console.WriteLine("Sending an e-mail message to {0} using the SMTP host {1}.", to.Address, client.Host);
            try
            {
                client.Send(message);
            }
            catch (SmtpFailedRecipientsException ex)
            {
                foreach (var t in ex.InnerExceptions)
                {
                    var status = t.StatusCode;
                    if (status == SmtpStatusCode.MailboxBusy || status == SmtpStatusCode.MailboxUnavailable)
                    {
                        Console.WriteLine("Delivery failed - retrying in 5 seconds.");
                        System.Threading.Thread.Sleep(5000); // Use better retry logic than this!
                        client.Send(message);
                    }
                    else
                    {
                        Console.WriteLine("Failed to deliver message to {0}", t.FailedRecipient);
                            // Do something better to log the exception
                    }
                }
            }
            catch (SmtpException ex)
            {
                // Here, if you know what to do about particular SMTP status codes,
                // you can look in ex.StatusCode to decide how to handle this exception
                // Otherwise, in here, you at least know there was an email problem
            }
            // Note that no other, less specific exceptions are caught here, since we don't know
            // what do do about them
        }
    }
}

请注意,此代码使用try / catch包围一小段代码。在该try / catch块中,如果抛出SmtpException或SmtpFailedRecipientsException,我们知道如何处理它。例如,如果我们要抓住IOException,我们就不知道它是什么意思,或者该怎么做。不应该捕获任何实际上不知道如何更正的异常,除非可以向异常添加信息,记录并重新抛出。

答案 2 :(得分:4)

try ... catch块用于捕获异常。在try块中,您放置了您期望的代码可能会引发异常。

如果没有异常发生,则try块中的代码按预期完成。如果有一个finally块,则接下来会执行。

如果发生异常,则执行跳转到第一个匹配的catch块的开头。一旦该代码完成,就执行finally块(如果存在)。执行不会返回try块。

答案 3 :(得分:1)

以下是一个例子:

try
{
    someFunctionThatWorks();

    functionThatThrowsAnException(); // As soon as this function throws an exception we are taken to the catch block

    anotherFunction();  // <-- This line will never get executed
}
catch(Exception e)
{
    // Here you can handle the exception, if you don't know how to handle it you should not be catching it
    // After this you will not be taken back to the try block, you will go right to the finally block
}
finally
{
    // Code here is always executed at the very end, regardless of whether an exception was thrown or not
}