2012-06-13 91 views
3

從庫中冒出異常的最佳方式是什麼?當我實現一個接口時,是否有一個好的或不好的做法,讓我的實現細節出現異常,從而給主叫方造成錯誤?我有以下實現,其中每個實現錯誤都遠離主叫方。它把我看作是實現問題分離的最乾淨的方式。但是,我到處讀到,你需要在未觸及的情況下冒出異常。如何在庫實現中冒泡/處理C#異常

public class OneException : Exception 
{ 
    public OneException() 
    { 
    } 

    public OneException(string message): base(message) 
    { 
    } 

    public OneException(string message, Exception innerException) 
     : base(message, innerException) 
    { 
    } 
} 

我的庫實現:

public class MyLib : IMyLib 
{ 
    public int Divide(int a, int b) 
    { 
     try 
     { 
      if (b == 1) throw new OneException(); 
      return a/b; 
     } 
     catch (OneException e) 
     { 
      throw new ApplicationException("Please do not divide by 1", e); 
     } 
     catch (Exception e) // divide by zero and others 
     { 
      throw new ApplicationException("Oops", e); 
     } 
    } 
} 

回答

2

選擇異常冒泡一個正確的策略取決於兩個主要因素:

  1. 你想提供有關的例外情況下來電者儘可能多的細節,可能嗎?
  2. 你想隱藏調用者的敏感異常數據嗎?

如果您想提供有關異常上下文的更多詳細信息,將異常包裝到某個更具體的異常中是一種很好的策略。這裏最明顯的例子是業務異常

如果您想隱藏異常的敏感數據,您可以考慮更換異常。當主叫方不信任時,這種方法通常用於服務。

注意:除非它不是正常程序流的一部分,否則不應該「吞併」異常。

1

作爲一般規則,只處理那些異常你可以處理

在您的圖書館實施中,您會看到不同的例外OneExceptionException並將其重新拋爲ApplicationException。我會認爲這是一個不好的做法,因爲你完全隱藏原始錯誤的含義。

如果客戶端代碼使用您的庫Divide()方法知道究竟發生了什麼,如果唯一發生異常的是異常ApplicationException,那麼不知道原因是什麼

你在這裏做的是拋出一個異常,用相同的方法捕捉它並重新拋出一個不同的異常。

讓異常泡到客戶端代碼,以便客戶端可以自己決定應當如何處理它 - 或者如果在所有

+0

你說「*唯一例外就是一個泛泛的ApplicationException,它不能提供關於原因的線索*」,但客戶端代碼可以將原始異常看作是內部異常......不是? – McGarnagle

+0

@dbaseman是的,但他們必須捕獲非特定的Exception類型並詢問InnerException。最好讓他們抓住他們所困擾的異常類型。 –

+0

@dbaseman:我同意格雷格所說的。另外,如果你只捕捉到非特定的'異常',你可以獲得比你想要的**更多的觀點**,而不僅僅是你**實際可以處理的**。你很可能想要捕獲一個**特定的異常類型,但是想要其他類型的**會進一步冒泡。 –

1

這取決於。如果您想處理異常並由於某些業務規則引發自定義異常,那麼請務必處理該異常並將其記錄下來或者引發一個新的自定義異常,就像您在示例代碼中發生異常的地方,divide by 1

另一個例子是,如果你是在一個表格中輸入的數據和獲得主鍵約束的例外,您可以捕獲該異常,並提高你自己定製的例外根據您的庫規格,或者你可以離開異常,因爲它是在調用代碼中處理的。

如果維護內部錯誤/異常日誌,處理庫中的異常可能會有幫助。您可以記錄該異常,然後將其拋出,以便它可以調用到調用代碼。 但恕我直言,如果你既不記錄日誌或提高定製的異常,它最好保持例外不變,以便可以在調用代碼中處理。

1

嘗試記錄異常,這總是一個好習慣。通過這種方式,客戶實際上會知道哪裏出了問題。

1

問問自己這些問題:

  • 作爲開發者,你想要什麼,消費者(主叫)瞭解你的圖書館嗎?

  • 作爲消費者,如果發生錯誤,您會想要什麼?

如果標準.Net標準不足以滿足您的需要,您只應該開始公佈您自己的異常類型。一個這樣的例子是與COM相關的錯誤 - 您可能希望爲特定的錯誤條件創建自定義異常,以避免拋出嵌入特殊數字的COMExceptions。

我會說在你的例子中OneException是浪費時間 - 爲什麼拋出,捕獲然後包裝和重新拋出作爲標準異常?爲什麼不先扔ApplicationException開始?這與使用異常來控制程序流程接近,這是一種反模式。

+0

如何使用自定義異常來爲頂級錯誤處理程序提供信息,以便知道如何通知用戶? – Lee

1

這兩個例外均由系統覆蓋。對於b = 1的情況,使用ArgumentOurOfRange異常,對於b = 0的情況使用DivideByZeroException。因此,對於非常簡單的示例庫,不需要創建額外的異常(這不是一個好習慣)。立即拋出異常是一個需求問題。在大多數情況下(最佳做法),您會使用try/catch(/ finally)拋出調用程序可以處理的異常。

1

Single Responsibility Principle一致,你應該照顧你的圖書館應該做的事情(如果可能的話)。否則,你應該讓調用者處理它。

在你的例子中,你正確地拋出一個被零除的異常。處理這不是你的圖書館的責任(除非你將它標榜爲「安全」的分水嶺方法)。錯誤是由不正確的客戶端輸入引起的,所以它應該是處理它的客戶端。

但是,您的OneException將是一個不尋常的拋出異常。爲什麼客戶不能分一個?它當然不會造成傷害。這大概是一個人爲的例子,但是除非真的有內部無法解決的問題,否則你不應該拋出異常。如果有人想分一個,爲什麼不應該允許他們這樣做?

良好的異常處理將通知客戶他們的輸入和/或系統故障的問題,而不是邏輯中的錯誤。