我对try,catch和finally执行的顺序感到很困惑。
我也想知道我应该何时使用try catch块以及我应该在try catch块中放置什么,我也想知道是否有一些异常来自try block然后如果采取对应于try块的操作然后一个是先执行或最后执行(这是 总是被执行),并且在执行这两个之后确实控制返回尝试阻止或者它永远放弃它。
答案 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
}