2017-07-06 22 views
0

以下面的最小示例拋出異常:C#:不覆蓋當前活動的一個

try { foo } 
finally { bar() } 

foo可以或可以不丟,並且bar()可以或可以不丟。 如果兩個函數都拋出,則bar()拋出的異常將覆蓋foo拋出的異常。但是,我需要看看foo引發的異常情況。我可以控制的唯一代碼是bar()。 在C++中,可以通過在bar()內檢查std::uncaught_exceptions來實現。 C#怎麼樣?

a check using Marshal.GetExceptionPointers(),但作爲回答狀態,這是一個可怕的黑客,在我的情況下,它是不夠的,因爲我的代碼需要在Mono運行,在沒有實現該功能。

語境:

在我的現實生活中的案例,foo是由圖書館用戶提供,可能會拋出各種異常的一大塊代碼,並bar()是由我提供的Dispose功能並自動調用。

+0

正如你可以控制代碼'bar'包裝在try/catch塊所以外面只能看到由'foo'拋出的異常。 –

回答

0

您需要手動編寫這樣的:

// Whether an exception has been thrown from the main block. 
bool hasMainException = false; 

try 
{ 
    foo(); 
} 
catch 
{ 
    // Record that exception has been thrown from main block, and rethrow. 
    hasMainException = true; 
    throw; 
} 
finally 
{ 
    // Execute secondary block within its own try-catch block. 
    try 
    { 
     bar(); 
    } 
    catch 
    { 
     // Only rethrow exception from secondary block if there isn't 
     // already an exception from the main block. 
     if (!hasMainException) 
      throw; 
    } 
} 

順便說一句,我需要達到非常相似,涉及Dispose方法,可以把你的用例的東西,所以我寫了一些擴展方法來實現這一目標,以及支持所有用例的各種策略。見DisposableExtensionsDisposeExceptionStrategy。您感興趣的策略是Subjugate

+0

正如我寫的,不幸的是,我可以控制的唯一代碼是'bar()'內的一個代碼,其他一切都是庫用戶的責任... –

+0

@mic_e:你是對的;我錯過了。除了你提到的破解之外,我不相信這是可以做到的。 – Douglas

0

這將

  • foo異常,即使異常被拋出bar
  • 如果從foo沒有發生異常,則從bar中拋出異常。
  • 如果沒有引發異常,則不拋出任何東西。
  • 保留來自任一異常的原始堆棧跟蹤。

    ExceptionDispatchInfo exceptionInfo = null; 
        try 
        { 
         foo(); 
        } 
        catch(Exception ex) 
        { 
         exceptionInfo = ExceptionDispatchInfo.Capture(ex); 
        } 
        finally 
        { 
         try 
         { 
          bar(); 
         } 
         catch(Exception ex) 
         { 
          exceptionInfo = exceptionInfo ?? ExceptionDispatchInfo.Capture(ex); 
         } 
        } 
        exceptionInfo?.Throw();