簡體   English   中英

在C#中處理異常的良好做法

[英]Good practices when handling Exceptions in C#

我在The Pragmatic Programmer和其他一些文章(包括Joel Spolsky的文章)中讀到,您只應在特殊情況下拋出Exception。 否則,您應該返回一個錯誤。

有時有可能(例如返回-1-0positive number ),但是在其他情況下則不可能。 我的意思是,如果您要返回一個類,則始終可以返回null ,但是我認為這樣做的目的是返回一些可以警告調用者發生了什么的東西。

如果我總是返回null ,那么我認為這沒什么用: 如果此方法返回null,則可能是由於A,B,C,D或E

那么,如何在C#中實現呢?

編輯:
在發布此問題幾小時后,我在這里看到了另一個問題,其中的問題本身與張貼的代碼是否是一種好的做法有關。

我看到這是做我在這里問的另一種方式。 鏈接在這里:

通用財產的劣勢?

何時引發異常的更好的規則是:

當您的方法無法執行其名稱所說明的操作時,將引發異常。

空值可用於表示您要求的內容不存在。 對於其他任何錯誤情況,均不應將其返回。

規則“僅在例外情況下拋出異常”對IMO無濟於事,因為它沒有給您基准來表明什么是例外,什么不是。 這就像說“只吃可食用的食物”。

通過使用數字,您將直接與Microsoft關於“例外”的建議相矛盾。 我發現使整個主題神秘化的最佳信息來源是Jeffrey Richter通過C#3編寫的CLR 此外, .NET Framework指南書中有關異常的材料也值得一讀。

引用MSDN

不要返回錯誤代碼。 異常是報告框架中的錯誤的主要方法。

您可以采用的一種解決方案是out參數,它可以得到結果。 然后,您的方法將返回bool ,就像您在框架中遇到的許多TryParse方法一樣。

要考慮的一個示例是int.TryParse 它將out參數用於解析值,並使用bool返回值指示成功或失敗。 bool可以與如果情況值得它枚舉或更復雜的對象來代替。 (例如,數據驗證可能會以確實可以保證一系列失敗的方式失敗,等等。)

.NET 4的替代方法是Tuple ...因此int.TryParse 可能是:

public static Tuple<int, bool> TryParse(string text)

下一種可能性是讓一個對象封裝整個結果,包括適當的故障模式。 例如,您可以向Task<T>詢問其結果,狀態以及失敗的異常。

所有這些僅在發生這種錯誤的情況下才是適當的。 它並不表示錯誤,僅表示錯誤的用戶輸入。 我真的不喜歡返回錯誤代碼-.NET中的異常更加常見。

Microsoft已記錄了.NET中錯誤處理的最佳做法

http://msdn.microsoft.com/zh-CN/library/8ey5ey87(VS.71).aspx

我建議遵循這些准則,因為它是.NET的標准,並且與其他.NET開發人員的沖突要少得多。

(請注意,我知道我發布了一個較舊的鏈接,但建議仍然存在。)

我還意識到,不同的平台在如何查看正確的錯誤處理方面會有所不同。 這可能是一個主觀的問題,但我會堅持上面所說的-在.NET中進行開發時,請遵循.NET准則。

您可能需要考慮遵循TryXXX模式,並為客戶端考慮幾個簡單的重載。

// Exception
public void Connect(Options o); 

// Error Code
public bool TryConnect(Options o, out Error e); 

喬爾·斯波斯基(Joel Spolsky)是錯的。 通過錯誤/返回碼返回狀態意味着您不能信任任何方法調用的結果-必須測試並處理返回的值。

這意味着返回此值的每個方法調用都會引入至少一個選擇點(或更多,取決於返回值的域),從而引入更多可能的代碼執行路徑。 所有這些都必須經過測試。

然后,假設Method1()和Method2()的約定是成功還是引發異常,則此代碼可能有1個流經它。

foo.Method(...) ;
bar.Method(...) ;

如果這些方法通過返回碼指示狀態,那么很快就會變得非常混亂。 只是返回一個二進制值:

bool fooSuccess = foo.Method(...);
if ( fooSuccess )
{
  bool barSuccess = bar.Method(...);
  if ( barSuccess )
  {
    // The normal course of events -- do the usual thing
  }
  else
  {
    // deal with bar.Method() failure
  }
}
else // foo.Method() failed
{
  // deal with foo.Method() failure
}

返回狀態碼,而不是引發異常

  • 使測試復雜化
  • 使代碼理解復雜化
  • 幾乎可以肯定會引入錯誤,因為開發人員不會捕獲並測試所有可能的情況(畢竟,您實際看到I / O錯誤發生的頻率是多少?)。

在調用該方法之前,調用方應進行檢查以確保所有內容都是笨拙的(例如,檢查文件是否存在。如果文件不存在,請不要嘗試打開它)。

強制執行您的方法的合同:

  • 前提條件。 調用方保證在方法調用之前這些都是正確的。
  • 后置條件。 被調用方保證在方法調用之后這些都是正確的。
  • 條件不變。 被告保證這些都是真的。

如果違反合同,則引發異常。 然后,如果發生任何意外情況,則引發異常。

您的代碼應嚴格管教。

僅當我確定在其他開發人員使用該代碼時不會產生任何誤解時,我才將這些值作為null引用或負索引值返回。 類似於LINQ函數IEnumerable<T>.FirstOrDefault IEnumerable<T>.First為空集合引發異常,因為預期它將返回第一個元素,並且空集合是一種例外情況

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM