1.重新拋出異常時使用 throw代替 throw ex
如果要重新拋出異常,請直接使用 throw ; 因為在 catch 塊中使用 throw ex 會丟失堆棧信息,throw 則不會。當(dāng)然,如果對異常不做任何處理,只是簡單地重新拋出,這種做法也是不可取的。
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch(Exception ex) { //…一些處理異常的代碼 // 直接使用 throw 而非 throw ex throw; } return result;
2.任何時候都不要吞沒異常
有些初學(xué)者為了不讓程序拋出異常,簡單地用空 catch 語句吞沒異常,這是典型的掩耳盜鈴,非常壞的習(xí)慣!對于異常,要做相應(yīng)的處理,至少也要重新拋出!
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch { // 錯誤,堅決杜絕!簡單粗暴地 // 吞沒了異常,典型的掩耳盜鈴 } return result;
3. 使用多個 catch 捕獲不同類型的異常
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch (HttpRequestException ex) { // 處理 HttpRequestException 的代碼 } catch (TaskCanceledException ex) { // 處理 TaskCanceledException 的代碼 result = null; }
4.使用過濾器更加精確地處理異常
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.Forbidden) { // 處理 403 錯誤的代碼 } catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { // 處理 404 錯誤的代碼 } return result;
5.使用日志記錄異常
產(chǎn)生異常后,應(yīng)使用日志系統(tǒng)記錄異常。記錄異常時,應(yīng)提供具體有意義的說明,同時記錄異常對象本身。
catch (FileNotFoundException ex) { // 不推薦,信息太過模糊 this.logger.logError(ex,”發(fā)生了一些錯誤”); // 不推薦,沒有記錄異常對象本身,丟失了堆棧等重要信息 this.logger.logError(“找不到請求的文件”); // 推薦,記錄異常對象的同時提供有意義的說明 this.logger.LogError(ex, “找不到請求的文件”); }
6.盡量使用系統(tǒng)預(yù)先定義好的異常
因為系統(tǒng)預(yù)定義的異常知曉度高,語義明確,讓第三方開發(fā)者更容易理解。比如:
- DivideByZeroException 零除異常
- ArgumentNullException,參數(shù)為空異常
- InvalidOperationException,非法操作異常
- IndexOutOfRangeException,索引超界異常
在絕大多數(shù)情況下,系統(tǒng)預(yù)定義的異常足夠使用了。只有在系統(tǒng)預(yù)定義異常無法滿足要求的時候,才考慮自定義異常。自定義的異常應(yīng)主要集中在業(yè)務(wù)和領(lǐng)域?qū)用?,異常的命名?yīng)該遵循 XxxException 的形式。