2009-07-10 122 views
3

我很確定我已經知道答案,但我仍然好奇在Try,Catch,Finally塊內處理錯誤的意見是什麼 - 但是當你重複自己。拋出異常VS返回錯誤,嘗試,捕捉,最後

順便說一句 - 我不是在談論用戶輸入 - 但使用一個例子,因爲它是明確的,短

考慮這段代碼...

try {  
    if (success) { 
     return someSuccessMessage; 
    } 
    else { 
     logError("User input not correct format"); 
     return someErrorMessage; // repeats itself 
    } 
} 
catch (Exception ex) { 
    logError(ex.Message); 
    return someErrorMessage; // repeats itself 
} 

說我們有一個函數,如果它失敗了,我們想返回一個錯誤信息,因爲這個異常是不相關的 - 我們的函數沒有成功,用戶也不需要任何額外的細節。

我一直認爲,如果你能處理錯誤,避免這種例外 - 因爲它不再是例外,但我想知道關於避免重複自己的觀點......你可以做以下,以避免重複自己......

try {  
    if (success) { 
     return someSuccessMessage; 
    } 
    else { 
     throw new Exception("User input not correct format"); 
    } 
} 
catch (Exception ex) { 
    logError(ex.Message); 
    return someErrorMessage; 
} 

這是不是最好的例子,但我會爲了簡潔,使重複碼點。

例外情況會導致性能損失,但對於這種情況有什麼想法?

+0

這是一個經典的控制流濫用例子的例子,這裏討論[爲什麼不使用異常作爲正常的控制流?](http://stackoverflow.com/q/729379/2444725) – Lightman 2015-10-30 10:36:58

回答

3

IMO,只有在外部可更正的情況下才應拋出異常。用戶輸入不正確的格式是已知的,不應該拋出任何異常。

將異常視爲災難性事件(數據中心着火,地震等)。這樣,您將看到處理「常規錯誤」和「異常」之間的區別。

是的,投擲和捕捉異常成本很多的表現,最好是避免它們。

在這種情況下
0

,其實我說的try/catch是不必要的,因爲如果你不是充分處理您的錯誤

但底部一個是我beleive風格應該用於更復雜的情況多

4

我質疑這裏關注的分離。除非這個函數是UI的一部分,否則它不應該關心錯誤消息。它而不是拋出異常。此方法的調用者(如果它是UI的一部分)可能希望產生顯示的錯誤消息。如果調用者是一個Web服務,那麼它會產生一個SOAP Fault,它可能不會使用相同的消息(如果它使用了任何消息)。

我也強烈建議你記錄ex.ToString()而不是ex.Message。

1

在你的情況下,我會只是返回錯誤消息(第一個例子),因爲拋出一個異常只有在下面3行看到它似乎有點奇怪。

一個完全不同的事情是,我通常避免在可能的情況下返回錯誤代碼 - 當出現錯誤情況時,我會通過異常並在最高級別捕獲錯誤代碼。通過這種方式,代碼不會隨處處理錯誤處理,而且更容易查看業務邏輯。在你的情況下(如果你控制它當然)返回成功的方法可能會拋出一個例外,如果失敗,並且你根本不需要問這個問題:)

確實是異常昂貴的C#,所以他們不應該被濫用。話雖如此,但如果出現錯誤,50ms左右的性能通常無關緊要,所以我傾向於使用它們來保持代碼清潔。

+0

我應該發佈一個更復雜的例子 - 簡單的例子只是爲了說明它 - 我正在談論一個更大的例子,更多的例子。試圖避免重複錯誤處理代碼。感謝您的答案 – Hugoware 2009-07-10 15:23:30

1

我同意你的例子中的邏輯,但是你認爲你在異常處理塊和你的程序測試中處理了什麼異常?我懷疑你的異常處理塊真的是「萬一發生了什麼事」。所以它真的歸結爲異常處理規則。

如果您不需要處理異常,並且它不通過不同的架構邊界,則不處理它。如果它位於組件邊界的邊緣,則可能需要將其包裹,將原始內容放在內部異常中。

如果從代碼中調用功能,您可能要用某種狀態表示(例如響應)來測試結果(HRESULT是其中的一個主要示例,0 == SUCCESS,!= 0 == failure)或使用例外。

測試編程錯誤或組件故障是您可以使用異常的地方,如果您正在驗證用戶在UI上的輸入,則可能只需使用邏輯並返回狀態代碼以幫助將錯誤傳達給用戶。

最後還想到本地化。如果您通過系統淹沒了英文錯誤消息,並將其呈現給您的法語用戶,但這並不會有用,並且您不希望在用戶界面上開始解析字符串以生成法語版本,所以例外是隻要異常的有效負載具有足夠的信息來生成有用的錯誤消息以供用戶採取糾正措施。

使用狀態碼,在組件之間緊密耦合,並且調用組件知道在不同的狀態條件下該做什麼。

順便說一句你可能想要使用ToString()來記錄堆棧跟蹤以及消息,因爲它會給你更多有用的信息來解決問題。

HTH

+0

感謝您的回答 - 順便說一句 - 這不是真正的代碼 - 它只是爲了說明這一點:) – Hugoware 2009-07-10 17:57:16

1

提取複製代碼伸到一個功能,如果你覺得自己的重複是一個問題。

error_code_t fail (string message) { 
    logError(message); 
    return someErrorMessage; 
} 

// ... 

try {  
    if (success) { 
     return someSuccessMessage; 
    } 
    else { 
     return fail("User input not correct format"); 
    } 
} 
catch (Exception ex) { 
    return fail(ex.Message); 
} 

說實話,我不會擔心在同一個函數中複製幾行代碼。

+0

我不同意最後一句話。它可以看起來像是「不那麼重要」乍一看去除了幾條線的重複,但想象在10種不同方法中有相同的「輕微重複」。 複製是邪惡的。正如聖艾修巴里所說:完美並非沒有什麼需要補充的時候,而是什麼時候沒有任何東西可以刪除。 – 2009-07-10 19:54:11