2011-04-06 70 views
3

什麼是異常處理,而不必把try/catch塊隨處可見的最佳做法?異常處理類

我必須創造出一種專門用於接收和處理異常一類的想法,但如果我想知道一個良好的設計理念。這樣的類將收到異常,然後再決定如何處理它根據其類型或錯誤代碼做,甚至可以解析爲特定的堆棧跟蹤信息,等

這裏是背後的基本思想和實現:

public class ExceptionHandler 
{ 
    public static void Handle(Exception e) 
    { 
     if (e.GetBaseException().GetType() == typeof(ArgumentException)) 
     { 
      Console.WriteLine("You caught an ArgumentException."); 
     } 
     else 
     { 
      Console.WriteLine("You did not catch an exception."); 
      throw e; // re-throwing is the default behavior 
     } 
    } 
} 

public static class ExceptionThrower 
{ 
    public static void TriggerException(bool isTrigger) 
    { 
     if (isTrigger) 
      throw new ArgumentException("You threw an exception."); 
     else 
      Console.WriteLine("You did not throw an exception."); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      ExceptionThrower.TriggerException(true); 
     } 
     catch(Exception e) 
     { 
      ExceptionHandler.Handle(e); 
     } 
     Console.ReadLine(); 
    } 
} 

我認爲這將是一個有趣的嘗試,因爲理論上你只需要在main()方法調用周圍需要一個或很少的try/catch塊,並讓異常類處理其他所有事情,包括重新拋出,處理,記錄,不管。

的思考?

+1

通過在你的'ExceptionHandler'類中重新拋出異常,你將失去先前的堆棧跟蹤。 – 2011-04-06 22:45:56

+0

有沒有辦法保存堆棧跟蹤? – 2011-04-06 22:52:18

+2

用'throw;'替換'throw e;'' – 2011-04-06 22:53:03

回答

5

其實是有一個很好的理由,爲什麼你看到在生產代碼類似的設計。

首先,這樣的設計不能幫助您減少代碼中try/catch對的數量(這應該是顯而易見的)。它可以幫你減少catch報表給定try數量,因爲你可能只是趕上System.Exception並轉發到ExceptionHandler ......

但接下來呢?

每一種異常需要進行不同的處理。 ExceptionHandler怎麼會知道該怎麼做?你可以嘗試多種方式,例如,以解決這個問題:

  1. ExceptionHandler派生,並把代碼中的虛擬方法來處理異常
  2. 通過一些Action<Exception>實例的處理程序,並讓它調用現在你需要創建一個全新的類各try塊,並覆蓋了一堆的方法的東西糟糕比你結束了:以前正確的一個

解決方案(1)會比你有什麼更糟糕之前(不是我)立即清楚特定類中的代碼如何適合程序的流程)。這也會讓另一個重要問題得不到解決:您可能需要上下文(訪問當前範圍中的變量)來正確處理異常。你將如何提供訪問這個上下文?解決方案(2)實際上最終會非常類似於編寫我們想要避免的catch塊(每個Action實際上將是catch塊的內容)。我們最終只會以更復雜和冗長的方式做同樣的事情。

也有其他的問題:

  • 我應該做ExceptionHandler如果它不能處理異常?再次投擲會導致您丟失原始堆棧跟蹤,實際上會破壞其中的所有良好信息。
  • 如果在ExceptionHandler有錯誤怎麼辦?你可以使用try/catch。你能相信你自己編寫的代碼到相同的程度嗎?

至於ExceptionThrower ...它可能提供什麼好處,而不是throw new Exception();

異常處理已經非常複雜,並且很難在不添加額外齒輪的情況下正確處理。特別是如果他們不給你買任何新東西的話。 不要這樣做。

+0

以一個簡單的控制檯應用程序爲例 - 如果我在執行UI的Main()方法中有一行代碼,並且試圖捕獲它,那麼不會在應用程序中發生任何異常,直到該catch塊?或者我錯過了什麼?爲什麼我需要超過單一的try/catch? – 2011-04-06 22:54:51

+2

@SeanThoman:因爲有些例外可以合理預期(例如試圖打開一個文件,你可能會得到一個'FileNotFoundException')以及意味着遊戲結束的異常(例如'ExecutionEngineException')。你無法從同一個地方合理地迴應;你需要不同的上下文。 – Jon 2011-04-06 22:59:06

+0

我認爲你可以通過配置處理類的邏輯,但它可能太複雜,並引入自己的錯誤,如你所說。如果這是一個非基於UI的應用程序,那該怎麼辦呢?只是一個工作應用程序按順序執行一些進程,完全放手,管理員只需定期檢查日誌以確保事情順利進行。你不希望應用程序停止運行某些例外,等等。 – 2011-04-06 23:07:56

6

OK,這可能不是你想要我通常對一般的異常處理類的想法過敏的答案,但...

。你幾乎可以聽到它本身就是一個矛盾。例外情況是例外事件。異常事件不能在一般的方式來處理,但需求量身定製的操控無論他們在哪裏出現,這基本上意味着你的代碼應該有兩點:

  1. 是防守有關,以避免在例外的任何輸入首先
  2. try..catch無論是有意義捕捉和處理異常(注意,這意味着,你不應該在所有的方法try..catch塊)

那麼,捕捉和處理異常的意義何在?簡而言之,您的代碼具有能夠處理異常的知識。如果沒有,請讓異常向上調用。 只有我認爲你應該捕獲所有異常,並在你的應用程序的頂層有一些通用的默認行爲。這通常是UI。

1

對不起,這不是一個好主意。當你在你的代碼中用正常的try/catch塊在相關部分周圍捕獲到一個異常時,你可以使用兩個關鍵信息來處理這個問題:異常的類型,還有發生異常。

根據您的安排,您必須處理所有異常,只知道它們是哪種類型的異常。您不再知道異常實際發生的位置,因此除了記錄日誌或向用戶顯示消息之外,您無法對此問題進行任何操作。此外,try/catch塊通常還包含一個finally塊,在這個塊中,即使拋出異常(如關閉流等),也可以確保事情發生。你在處理這件事的安排上沒有任何辦法。

適當的異常處理可能會非常棘手,並且沒有任何靈丹妙藥可以使它變得簡單明瞭。如果有的話,.Net將已經合併它。

+0

您可以通過使用堆棧跟蹤來了解它發生的位置......但我確實看到了您的觀點。由於使用'throw e'會破壞堆棧跟蹤,而只使用'throw'只能在catch塊中使用,所以似乎很棘手..您必須記錄堆棧跟蹤或編程地在堆棧跟蹤之前執行某些操作E」。 – 2011-04-06 23:00:48

+0

你的意思是如果你寫了一個堆棧跟蹤解析器(yay!),你可以推斷出現異常的地方。沒錯,但是你仍然需要在某處放置代碼,以便對特定的異常類型和位置信息做出適當的響應。爲什麼不把它放在正常的catch塊中,就在導致問題的代碼的下面? – MusiGenesis 2011-04-06 23:05:04

1

我們在我們的代碼庫中有一個類,它與您提議的代碼具有非常相似的簽名,現在我可以告訴您它只有痛苦和痛苦!

爲什麼你的代碼中有這麼多的try-catch塊?你能舉一些例子嗎?異常的性質「非常」,即不那麼頻繁!你不僅應該經常捕捉異常,而且每個異常都是不同的,並且在一種情況下工作的相同樣板代碼可能不適用於許多其他情況。沒有人說異常處理很容易(或者生成緊湊的代碼) - 你應該認爲仔細關於你需要捕捉異常並適當處理它的每種情況 - 避免捕捉你不需要處理的異常。

+0

我實際上沒有那麼多嘗試抓塊......但我很好奇這個想法。 – 2011-04-06 23:05:21