try catch和finally块的执行顺序

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

我也想知道我应该何时使用try catch块以及我应该在try catch块中放置什么,我也想知道是否有一些exception出现在try块然后如果对应于try块采取了一个动作然后执行哪一个第一次捕获或最后(总是被执行),并且在执行这两个之后确实控制返回尝试阻止或者它永远放弃它。

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

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

代码A将被执行。 如果一切顺利(即在A执行时没有exception被抛出),它将最终进入,因此代码C将被执行。 如果在执行A时抛出exception,则它将转到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部分来捕获问题并执行一些有用的操作,例如通知用户,将exception记录到日志文件中,再试一次或尝试一些您认为可能有用的东西而不是您尝试过的东西本来。

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

看看这里了解更多信息:

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

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

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

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

您应该只catch实际可以纠正的exception,并且只有在您期望它们时才能catch 。 否则,让调用者处理exception – 或不。

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

然后, finally “终于”执行了。


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

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

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

事实是上面的代码应该替换为以下代码:

 // Do something here 

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

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


以下是以合理方式使用exception的示例(来自MSDN)。 它是SmtpFailedRecipientsException类文档中示例的修改forms。

 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 ,我们就不知道它是什么意思,或者该怎么办。 除非将信息添加到exception,记录并重新抛出,否则不应捕获任何您实际上不知道如何更正的exception。

这是一个例子:

 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 }