2012-09-26 63 views
2

我要實現自定義的異常處理在我的圖書館,讓我知道發生了異常的,所以我這樣做:從catch塊中拋出嵌套異常......這是明智的嗎?

try 
{ 
    DoSomething(); 
} 
catch(Exception ex) 
{ 
    //LibraryException refers to any exception in the libraries exception hierarchy 
    throw new LibraryException(ex.Message, ex); 
} 
  • 如果這避免?

  • 它是否有任何性能影響?

  • 捕捉,嵌套和重新拋出異常的含義是什麼?

+0

想知道,這是如何幫助你知道發生異常的地方?所有異常都有一個堆棧跟蹤,爲什麼你不能使用它? – Hogan

+0

這已被問到之前,請參閱:http://stackoverflow.com/questions/4761216/c-throwing-custom-exception-best-practices http://stackoverflow.com/questions/22623/net-throwing-exceptions- best-practices –

回答

3

唯一的潛在問題是您正在捕捉非特定的Exception,因此不符合exception handling guidelines

下列情況之一的將是更符合的這些準則:

try 
{ 
    DoSomething(); 
} 
catch(SomeException ex) 
{ 
    throw new LibraryException(ex.Message, ex); 
} 

或:

try 
{ 
    DoSomething(); 
} 
catch(Exception ex) 
{ 
    if (ex is SomeException || ex is SomeOtherException) 
    { 
     throw new LibraryException(ex.Message, ex); 
    } 
    throw; 
} 

至於性能,一旦異常被拋出,一些特殊情況已經發生了,你可能不關心包裝它的小額外開銷。

從評論:

在大多數情況下

當庫選擇包裝異常,將包裹被扔進庫的範圍之外的所有異常,...

我不同意與此,雖然它是公認的主觀。它包裝異常庫的一個例子是SqlMembershipProvider,它封裝了一些具體的例外在ProviderException,例如:

try 
{ 
    new Regex(this._PasswordStrengthRegularExpression); 
} 
catch (ArgumentException exception) 
{ 
    throw new ProviderException(exception.Message, exception); 
} 

但其他異常,如SqlException呼叫者不能指望處理傳播展開。

+1

在大多數情況下,當庫選擇包裝異常時,它將包裝拋出庫範圍之外的所有異常,因此全局捕獲將是合適的。如果你打算只包裝某些類型的例外,那麼這將是適當的。噢,我會用幾個'catch'塊,而不是用'is'來檢查異常的類型,但這更偏好個人喜好。 – Servy

+1

@Servy,我不同意全球捕獲,請參閱更新。 – Joe

+0

@Joe,我不得不同意Servy,即使[Microsoft](http://msdn.microsoft.com/en-us/library/ms182137.aspx)也不熱衷於捕捉任何一般的異常。 – iMortalitySX

2

這是一個很好的做法,如果它爲您的架構增加了抽象和/或清晰度。

它使異常更加明確,並可能隱藏更高層的低層細節。例如,在數據訪問層中,您可能會捕獲SqlExceptions並拋出DataAccessExceptions,因此較高層不會「知道」您正在使用SQL Server作爲數據存儲。

2

這應該避免嗎?

這是一個偏好問題。在某些情況下,它可能是有利的,在一些有害的情況下,並且在大多數情況下,其中一些是有利的。在某些情況下,您可以通過現有的庫看到這一點,並且還有其他庫不選擇。

它是否有任何性能影響?

也許,是的,但我懷疑它是真正重要的。開始的時候並不便宜。

捕捉,嵌套和重新拋出異常的含義是什麼?

優點:

  • 有人叫你的方法可以很容易地捕獲從您的庫拋出的異常。
  • 從調用者隱藏庫的實現細節。
  • 允許調用者輕鬆地從您的庫中捕獲異常。沒有這個,如果他們試圖捕捉一個無效的參數異常,它可能來自你的庫或其他代碼。他們可能只想捕獲從其他地方拋出的參數異常。

缺點:

  • 這是很難趕上只是可能,而不是追趕別人已經從資料庫中拋出的異常類型之一。
  • 它顯示時會在異常文本中增加大量混亂。
1

好吧,作爲一個真正快速的概述,當try catch塊中捕獲到異常時,它必須爲跟蹤收集整個堆棧。拋出任何類型的異常實際上是相當昂貴的,但是它會以指數形式出現,所以當你將catch塊嵌入catch塊時。所以,如果你確切知道你爲什麼拋出它並計劃通過嘗試來處理它,那麼你真的應該只拋出一個異常。當你創建一個API時,情況就大多如此,並且無法預測其他開發人員如何使用你的庫。

如果你正在爲自己的應用程序編寫代碼,你應該避免拋出一個異常,因爲你只是把它扔給自己(基本上)。在這種情況下,你應該處理髮生異常時不會拋出你自己的情況。

與Python(我喜歡但是不同的範例)和其他「oops」語言不同,通過C#中的異常處理來控制流是不好的做法。

Under C# how much of a performance hit is a try, throw and catch block

Arguments for or against using try catch as logical operators

Exception Handling in C#

C# Exception (Check this one out)

CA1031: Do not catch general exceptions

+0

hmmm ....聲明「通過異常處理控制流是不好的」是真實的。但在這個問題中情況並非如此,這個問題不是關於控制正常流量,而是關於異常情況。無論如何,該方案將會崩潰 - 不會有很大的性能影響。 – Hogan

1

在背景下,拋出更具體的異常通常是一個好主意,提供 LibraryException來自您自己的問題域,並向開發人員提供更具體的信息,以便他們可以說「啊,庫異常意味着發生某類錯誤之一。」

嘗試捕獲確實強加了他們自己的性能開銷,但是我沒有看到任何東西使得這個塊比其他任何類似塊更差。