如果finally塊拋出異常,什麼恰好發生?如果finally塊引發異常,會發生什麼情況?
具體來說,如果在finally代碼塊中途拋出異常,會發生什麼情況。請調用此塊中的其餘語句(之後)嗎?
我知道異常會向上傳播。
如果finally塊拋出異常,什麼恰好發生?如果finally塊引發異常,會發生什麼情況?
具體來說,如果在finally代碼塊中途拋出異常,會發生什麼情況。請調用此塊中的其餘語句(之後)嗎?
我知道異常會向上傳播。
如果一個finally塊拋出異常什麼恰好發生?
該異常傳播出來,並將(可)在更高層次上處理。
您的finally塊將而不是超出拋出異常的位置。
如果finally塊在處理先前的異常期間執行,那麼第一個異常將丟失。
C#4語言規範§ 8.9.5如果finally塊引發另一個異常,則終止對當前異常的處理。
+1:**完全**回答問題的唯一答案 – 2010-05-26 08:30:39
如果從'try'塊引發異常,它將被吃掉。 – 2010-05-26 08:36:25
除非它是'ThreadAbortException',否則整個finally塊將首先完成,因爲它是一個關鍵部分。 – 2013-10-08 21:23:30
它引發一個異常;)您可以在其他catch子句中捕獲該異常。
public void MyMethod()
{
try
{
}
catch{}
finally
{
CodeA
}
CodeB
}
通過CODEa所和CodeB拋出的異常的處理方式是一樣的。
在finally
塊拋出的異常有沒有什麼特別的,把它作爲由代碼B.
你能否詳細說明一下?與例外情況相同的是什麼意思? – 2010-05-26 08:36:24
對不起,看到我的編輯 – 2010-05-26 08:41:08
異常拋出這樣的,我通常開在Visual Studio中的空控制檯應用程序項目,寫一個小樣本問題程序:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
catch (Exception ex)
{
Console.WriteLine("Inner catch block handling {0}.", ex.Message);
throw;
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
當你運行程序,你會看到在catch
和finally
塊被執行的確切順序。請注意,該代碼在finally塊被拋出後的異常將不被執行(事實上,在這個示例程序的Visual Studio甚至會提醒你它已經檢測不到的代碼):
Inner catch block handling exception thrown from try block. Inner finally block Outer catch block handling exception thrown from finally block. Outer finally block
附加註釋
正如邁克爾Damatov指出,從try
塊中的異常會被「吃掉」,如果你不以(內)catch
塊處理。事實上,在上面的例子中,重新拋出的異常不會出現在外部catch塊中。爲了讓這個就更清楚了看看下面略作修改樣本:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
正如你可以從輸出的內部異常「丟失」看(即忽略):
Inner finally block Outer catch block handling exception thrown from finally block. Outer finally block
因爲你拋出你的內部捕獲異常,在這個例子中永遠不會達到'內部finally塊' – 2010-05-26 08:43:52
@Theofanis Pantelides:不,'finally'塊將會(幾乎)總是被執行,這成立在這種情況下,對於內部finally塊(只是自己嘗試一下示例程序)(如果發生不可恢復的異常,例如'EngineExecutionException',finally塊不會被執行,但在這種情況下,程序將立即終止無論如何) – 2010-05-26 08:59:23
+1:一個比僅僅引用規範更有用的答案 – 2010-05-26 11:11:19
如果有異常掛起(當try
塊具有finally
但沒有catch
),新的異常替換之一。
如果沒有未處理的異常,它就像在finally
塊之外拋出異常一樣工作。
如果*有*匹配的catch語句塊(重新拋出異常),則異常可能也會掛起。 – stakx 2015-01-19 22:05:36
在另一個異常處於活動狀態時拋出異常將導致第一個異常被第二個(稍後)異常取代。
下面是一些代碼,說明發生了什麼:
public static void Main(string[] args)
{
try
{
try
{
throw new Exception("first exception");
}
finally
{
//try
{
throw new Exception("second exception");
}
//catch (Exception)
{
//throw;
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
值得注意的是,清理「嚴重」異常是可能的,該異常只會在特定代碼塊之外被捕獲,以引發異常並在其中被捕獲和處理。使用異常過濾器(在vb.net中可用,但不是C#)可以檢測到這種情況。代碼可以「處理」它的代碼並不多,但如果使用任何類型的日誌框架,它幾乎肯定值得記錄。清理過程中發生異常的C++方法觸發系統崩潰很醜陋,但有例外消失是恕我直言可怕的。 – supercat 2012-11-30 16:53:36
幾個月前,我還遇到這樣的事情,
private void RaiseException(String errorMessage)
{
throw new Exception(errorMessage);
}
private void DoTaskForFinally()
{
RaiseException("Error for finally");
}
private void DoTaskForCatch()
{
RaiseException("Error for catch");
}
private void DoTaskForTry()
{
RaiseException("Error for try");
}
try
{
/*lacks the exception*/
DoTaskForTry();
}
catch (Exception exception)
{
/*lacks the exception*/
DoTaskForCatch();
}
finally
{
/*the result exception*/
DoTaskForFinally();
}
爲了解決我犯了一個實用工具類,像
class ProcessHandler : Exception
{
private enum ProcessType
{
Try,
Catch,
Finally,
}
private Boolean _hasException;
private Boolean _hasTryException;
private Boolean _hasCatchException;
private Boolean _hasFinnallyException;
public Boolean HasException { get { return _hasException; } }
public Boolean HasTryException { get { return _hasTryException; } }
public Boolean HasCatchException { get { return _hasCatchException; } }
public Boolean HasFinnallyException { get { return _hasFinnallyException; } }
public Dictionary<String, Exception> Exceptions { get; private set; }
public readonly Action TryAction;
public readonly Action CatchAction;
public readonly Action FinallyAction;
public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null)
{
TryAction = tryAction;
CatchAction = catchAction;
FinallyAction = finallyAction;
_hasException = false;
_hasTryException = false;
_hasCatchException = false;
_hasFinnallyException = false;
Exceptions = new Dictionary<string, Exception>();
}
private void Invoke(Action action, ref Boolean isError, ProcessType processType)
{
try
{
action.Invoke();
}
catch (Exception exception)
{
_hasException = true;
isError = true;
Exceptions.Add(processType.ToString(), exception);
}
}
private void InvokeTryAction()
{
if (TryAction == null)
{
return;
}
Invoke(TryAction, ref _hasTryException, ProcessType.Try);
}
private void InvokeCatchAction()
{
if (CatchAction == null)
{
return;
}
Invoke(TryAction, ref _hasCatchException, ProcessType.Catch);
}
private void InvokeFinallyAction()
{
if (FinallyAction == null)
{
return;
}
Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally);
}
public void InvokeActions()
{
InvokeTryAction();
if (HasTryException)
{
InvokeCatchAction();
}
InvokeFinallyAction();
if (HasException)
{
throw this;
}
}
}
而且這樣
try
{
ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally);
handler.InvokeActions();
}
catch (Exception exception)
{
var processError = exception as ProcessHandler;
/*this exception contains all exceptions*/
throw new Exception("Error to Process Actions", exception);
}
使用這樣的問題
但如果你想使用參數和返回類型是一個其他故事
我不得不這樣做來捕獲一個錯誤,試圖關閉一個從未打開的流,因爲有一個異常。
errorMessage = string.Empty;
try
{
byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent);
webRequest = WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "text/xml;charset=utf-8";
webRequest.ContentLength = requestBytes.Length;
//send the request
using (var sw = webRequest.GetRequestStream())
{
sw.Write(requestBytes, 0, requestBytes.Length);
}
//get the response
webResponse = webRequest.GetResponse();
using (var sr = new StreamReader(webResponse.GetResponseStream()))
{
returnVal = sr.ReadToEnd();
sr.Close();
}
}
catch (Exception ex)
{
errorMessage = ex.ToString();
}
finally
{
try
{
if (webRequest.GetRequestStream() != null)
webRequest.GetRequestStream().Close();
if (webResponse.GetResponseStream() != null)
webResponse.GetResponseStream().Close();
}
catch (Exception exw)
{
errorMessage = exw.ToString();
}
}
如果在創建WebRequest的,但在
using (var sw = webRequest.GetRequestStream())
發生的連接錯誤,則最終會趕上異常試圖關閉了它認爲由於WebRequest的已經建立了開放連接。
如果最後沒有必須內一個try-catch,而清理的WebRequest
if (webRequest.GetRequestStream() != null)
這個代碼將導致未處理的異常從那裏代碼將退出,不妥善處理所發生的錯誤,因此造成調用方法的問題。
希望這有助於作爲一個例子
快速(和相當明顯)段,以拯救「原始異常」(在try
塊拋出)和犧牲「終於例外」(在finally
塊拋出),萬一原對你更重要:
try
{
throw new Exception("Original Exception");
}
finally
{
try
{
throw new Exception("Finally Exception");
}
catch
{ }
}
在執行上面的代碼,「原來的異常」向上傳播調用堆棧,以及「最後例外」丟失。
異常傳播開來,應該在更高級別處理。如果未在較高級別處理異常,則應用程序崩潰。 「finally」塊的執行停止在拋出異常的地方。
無論是否存在異常,「finally」塊都保證執行。
如果說「最後」塊被一個異常發生在try塊,後執行
,如果該異常沒有被處理
,如果finally塊拋出異常
然後,try塊中發生的原始異常丟失。
public class Exception
{
public static void Main()
{
try
{
SomeMethod();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void SomeMethod()
{
try
{
// This exception will be lost
throw new Exception("Exception in try block");
}
finally
{
throw new Exception("Exception in finally block");
}
}
}
爲什麼不試試呢?但在這類事情上,我最喜歡的是在finally之前返回,然後從finally塊返回其他東西。 :) – ANeves 2010-05-26 09:38:18
必須執行finally塊中的所有語句。它不能有回報。 http://msdn.microsoft.com/en-us/library/0hbbzekw(VS.80).aspx – 2010-05-26 12:02:08