我需要將定時事件中引發的例外冒泡并在事件處理程式背景關系之外進行處理。我已經讀過System.Threading.Timers可以做到這一點,前提是,如該問題的答案中所述,例外被捕獲在回呼方法中,并使用一種機制來重新拋出它。使用這個例子作為指導,我創建了一個拋出的事件處理程式和一個應該使用物件捕獲并重新拋出例外的方法IProgress:
void ThrowerThreaded() {
var progress = new Progress<Exception>((ex) => {
throw ex;
});
Timer timer = new Timer(x => onTimerElapsedThrow2(progress), null, 10, -1);
Thread.Sleep(1000);
}
void onTimerElapsedThrow2(IProgress<Exception> progress) {
try {
throw new Exception();
} catch (Exception ex) {
progress.Report(ex);
}
}
然后我寫了一個單元測驗來看看例外是否會冒泡:
[TestMethod]
public void TestThreadedTimerThrows() {
Assert.ThrowsException<Exception>(ThrowerThreaded);
}
測驗用例失敗,表明沒有拋出例外。如果我除錯測驗用例,我可以清楚地看到例外被捕獲并重新拋出,ThrowerThreaded()但是該方法仍然繼續并正常存在。為什么例外仍然被抑制?
uj5u.com熱心網友回復:
我猜ThrowerThreaded是在后臺執行緒上運行。這意味著它沒有同步背景關系,因為它們旨在同步 UI 應用程式。這意味著在執行緒池上呼叫回呼:
通過在構造實體時捕獲的 SynchronizationContext 實體呼叫提供給建構式的任何處理程式或使用 ProgressChanged 事件注冊的事件處理程式。如果在構造時沒有當前 SynchronizationContext,則將在 ThreadPool 上呼叫回呼。
在執行緒池執行緒上重新拋出例外可能會殺死該執行緒,我有點驚訝它沒有殺死應用程式,但這種行為可能會被您正在使用的測驗框架覆寫。
要解決這個問題,您確實需要在回呼中處理例外,而不是重新拋出它。如果您不處理例外,誰應該處理?有一個unhandledExceptionEvent,但它用于在您關閉應用程式之前進行記錄。
ThrowerThreaded您可以通過將例外處理委托給的回呼來處理例外。另一種選擇是創建一個TaskCompletionSource允許您回傳任務,并通過在源上呼叫 SetException 將任務設定為“失敗”。
重新拋出相同的例外物件也是不好的做法,因為您將丟失呼叫堆疊,您應該將例外包裝在拋出的新例外中。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/450268.html
上一篇:原子交換兩個指標的值
下一篇:Python調度執行緒
