2009-09-28 68 views
39

在我的應用程序中,如果特定類的屬性爲null或空(如果是字符串),則需要拋出異常。我不確定在這種情況下使用什麼樣的最佳例外。我討厭創建一個新的異常,我不確定在這種情況下ArgumentNullException是否合適。屬性不能爲空時使用什麼異常類型?

我應該創建一個新的異常還是有我可以使用的異常?

我不介意拋出一個ApplicationException。

+0

請記住太屬性是語法加糖的方法。 – Dykam 2009-09-28 19:00:49

+0

一個相關的有趣的討論:http://stackoverflow.com/questions/1488472/best-practices-throwing-exceptions-from-properties – Joren 2009-09-28 19:08:52

回答

65

MSDN guidelines for standard exceptions狀態:

做使用價值財產 制定者的隱含值參數的名稱。

以下代碼示例顯示一個 屬性,如果調用者傳遞一個空參數 ,該屬性將拋出異常。

public IPAddress Address 
{ 
    get 
    { 
     return address; 
    } 
    set 
    { 
     if(value == null) 
     { 
      throw new ArgumentNullException("value"); 
     } 
     address = value; 
    } 
} 

此外,MSDN guidelines for property design說:

避免拋出從 屬性獲取例外。

屬性獲取者應該是簡單的 操作沒有任何先決條件。 如果一個吸氣劑可能會拋出異常, 考慮重新設計屬性爲 是一種方法。此建議 不適用於索引器。索引器 由於無效的 參數而引發異常。

它是有效的,可接受的從屬性的setter拋出 例外。

在二傳手所以扔ArgumentNullExceptionnull,並ArgumentException對空字符串,什麼事都不做的吸氣劑。由於setter拋出並且只有你有權訪問後臺字段,所以很容易確保它不包含無效值。吸取投擲是毫無意義的。這可能是使用Debug.Assert的好地方。

如果你真的不能提供適當的默認的話,我想你有三種選擇:

  1. 只返回無論是在性能和​​文檔這種行爲作爲使用合同的一部分。讓調用者處理它。您可能還需要構造函數中的有效值。儘管這可能完全不適合你的應用程序。

  2. 通過方法替換屬性:傳遞無效值時引發的setter方法,以及在屬性從未分配有效值時拋出InvalidOperationException的getter方法。

  3. 從吸氣劑中拋出InvalidOperationException,因爲您可以認爲「屬性從未分配過」是無效狀態。雖然你通常不應該從getter中拋出,但我想這可能是一個例外的好理由。

如果您選擇選項2或3,您還應該包括一個TryGet-方法返回一個bool這表明如果屬性已被設置爲一個有效的值,如果是返回一個out參數值。否則,你強制呼叫者準備好處理InvalidOperationException,除非他們先前已經設置了屬性並因此知道它不會拋出。比較int.Parseint.TryParse

我建議使用選項2與TryGet方法。它不違反任何指導原則,並對調用代碼施加最低要求。


關於其他建議
ApplicationException是太一般。 ArgumentException對於null有點過於籠統,否則就很好。MSDN docs again

不要拋出最具體的(最派生)的例外是 合適。例如,如果一個方法 收到一個空值(基於Visual的 中的Nothing),它應該拋出 System.ArgumentNullException,而不是基類型的 System.ArgumentException。

其實你不應該使用ApplicationException在所有(docs):

不要從T派生自定義異常:System.Exception類,而不是T:System.ApplicationException類。

它最初認爲自定義異常應該派生自ApplicationException類;然而,這並沒有被發現增加重要價值。有關更多信息,請參閱處理異常的最佳實踐。

InvalidOperationException不旨在用於當所述參數的方法或屬性是無效的,但是,用於當操作作爲一個整體是無效的(docs)。它不應該從setter丟棄:

如果處於不適當的狀態,請拋出System.InvalidOperationException異常。給定對象的當前狀態,如果屬性集或方法調用不適合,則應引發System.InvalidOperationException。例如,寫入已打開讀取的System.IO.FileStream應該會引發System.InvalidOperationException異常。

順便提及,InvalidOperationException是用於當操作是用於對象的當前狀態無效如果整個課程的操作始終無效,則應使用NotSupportedException

+0

@Joren,@Vadim表示他需要一個默認講師,並且沒有合理的默認值,所以僅僅監視setter對於他的場景來說是不夠的。 – bdukes 2009-09-28 18:19:57

+0

你說得對,我會編輯我的答案。 – Joren 2009-09-28 18:29:32

+0

@Joren,優秀的迴應。 – Vadim 2009-09-28 20:02:12

1

構造函數是否將它設置爲非空值?如果是這樣,我只會從引用者那裏拋出ArgumentNullException

4

我會拋出一個InvalidOperationException。 MSDN說它「在方法調用對於對象的當前狀態無效時引發」。

+1

我不認爲這適用於這種情況。 InvalidOperationException只應在被調用的對象無效時使用。在這種情況下,被調用的對象是100%有效的,它是該方法的參數是無效的。 – JaredPar 2009-09-28 17:52:37

+2

如果對象處於無法使用屬性設置器的狀態,則會拋出'InvalidOperationException'。也就是說,*操作*本身是無效的。 MSDN文檔給出了「寫入已打開閱讀的System.IO.FileStream」的示例。 – Joren 2009-09-28 17:54:28

+0

我想我們並不知道所謂的確切場景。我正在假設我們正在調用一個類的方法,並試圖在該方法內使用該類的屬性。在這種情況下,該對象對於被調用的方法無效(因爲在調用方法之前需要設置該屬性)。 看起來@JaredPar正在考慮參數未初始化的場景。在那種情況下,他提出的「ArgumentException」是最有意義的。 – bdukes 2009-09-28 18:15:17

2

嗯,這不是一個參數,如果你引用一個類的屬性。所以,你不應該使用ArgumentException或ArgumentNullException。

NullReferenceException會發生,如果你只是讓事情孤單,所以我認爲這不是你想要的。

因此,使用ApplicationExeption或InvalidOperationException可能是您最好的選擇,確保給出一個有意義的字符串來描述錯誤。

+1

我很確定在.NET Framework中有一些類從屬性的setter中拋出ArgumentException。我不記得確切的地方,但我記得遇到它。你可能會認爲它可能不是「正確的」,但是不管框架是否已經開創了先例。 – Tinister 2009-09-28 17:40:00

2

如果有人試圖指定爲空,那麼拋出ArgumentNullException是相當合適的。

屬性不應該拋出讀取操作。

+0

你從哪裏獲得一個屬性永遠不會拋出讀操作的想法?它肯定可以輕鬆發生。 – 2009-09-28 17:37:52

+1

@John我不認爲他的觀點是它不能但不能。 – 2009-09-28 17:41:56

+1

@John Fisher:Cwalina,Krzystof和Brad Abrams:「Framework Design Guidelines,Conventions,Idioms,and Patterns for Reusable .Net Libraries」,Addison-Wesley,2006年。 121 - 其他來源。 – 2009-09-28 17:48:12

1

如果問題是一個參數的成員,而不是參數本身,那麼我認爲最好的選擇是更通用的ArgumentExceptionArgumentNullException在這裏不起作用,因爲參數實際上不是null。相反,您需要更通用的「您的參數有問題」異常類型。

的構造函數的詳細信息將是非常合適的位置

+0

你是什麼意思「構造函數的詳細消息」?我必須有一個默認的構造函數。 – Vadim 2009-09-28 17:43:21

+0

@Vadim關於爲什麼拋出參數異常的詳細原因。例如「參數foo的屬性Blah必須爲非null」 – JaredPar 2009-09-28 17:50:54

+0

@Vadim,他指的是異常的構造函數,而不是您的對象的構造函數。 – bdukes 2009-09-28 18:16:26

1

如果它不能爲空或空的,有你的二傳手不允許空或空值,或引發ArgumentException如果是這樣的情況。

另外,要求在構造函數中設置屬性。

這樣你強制一個有效的值,而不是稍後回來,並說你不能確定帳戶餘額,因爲沒有設置帳戶。

但是,我同意bduke的迴應。

+1

我必須有默認的構造函數。 – Vadim 2009-09-28 17:41:39

+0

你不能把一些有效的默認值,我把它在構造函數? – 2009-09-28 17:43:24

+1

不幸的是我不能玩猜謎遊戲。我不知道在運行時應該設置什麼值。 – Vadim 2009-09-28 17:48:44

1

有一個將ArgumentNullException的解釋擴展爲意義「字符串參數爲null或空」的先例:在這種情況下,System.Windows.Clipboard.SetText將引發ArgumentNullException。

所以我不會在您的屬性設置器中使用此代碼而不是更常規的ArgumentException中發現任何錯誤,前提是您要記錄它。

0

只要錯誤信息對開發人員有幫助就拋出。無論如何,這類例外不應該發生在開發之外。

相關問題