2010-12-15 53 views
17

關閉我的頭頂,我能想到的4種方式檢查null參數:測試前提條件的不同方法的優缺點?

Debug.Assert(context != null); 
Contract.Assert(context != null); 
Contract.Requires(context != null); 
if (context == null) throw new ArgumentNullException("context"); 

我一直使用的最後一個方法,但我剛纔看到的代碼片段使用Contract.Requires,我不熟悉。 每種方法的優缺點是什麼?有其他方法嗎?


在VS2010 W/ReSharper的,

  • Contract.Assert警告我說,表達始終是真實的(它是如何知道的,我不太清楚......不能HttpContext的爲空? ),
  • Contract.Requires被淡化了,它告訴我的編譯器不會調用的方法(我假設,因爲前者的原因,它永遠不會爲空),並
  • 如果我改變的最後選擇context != null所有代碼如下翅膀漸漸消失,它告訴我代碼是啓發式無法達到的。

因此,看起來最後3種方法有一些內置到VS靜態檢查器中的智能,而Debug.Assert是愚蠢的。

+0

問題不明確。你是否真的試圖一次全部使用它們? – 2010-12-15 01:22:59

+0

@Matthew:不知道這怎麼不清楚......不,我沒有試圖一次性使用它們。我做了一個類似的代碼片段來說明你可以檢查null的不同方式。 – mpen 2010-12-15 02:59:22

+0

這就是我從問題的其餘部分想到的,但是你使用的語法呈現很奇怪。 – 2010-12-15 03:06:00

回答

12

我的猜測是有一個合約適用於接口IHttpHandler.ProcessRequest,它要求上下文!= null。接口契約由其實現者繼承,所以你不需要重複需求。事實上,您不能添加額外的Requires語句,因爲您僅限於與界面合同相關的要求。

我認爲區分指定合同義務和簡單執行空檢查很重要。您可以在運行時實施空檢查並引發異常,以通知開發人員他們正在正確使用您的API。另一方面,契約表達式實際上是一種元數據形式,它可以由合約重寫器來解釋(以引入之前手動實施的運行時異常),也可以由靜態分析器來解釋,它可以用它們來推理了解您的應用程序的靜態正確性。這就是說,如果你正在一個你正在積極使用代碼契約和靜態分析的環境中工作,那麼最好把斷言放在契約形式中,以便利用靜態分析。即使您沒有使用靜態分析,您仍然可以通過使用合約爲以後的利益敞開大門。需要注意的主要問題是您是否配置了項目來執行重寫,否則合約不會像您期望的那樣導致運行時異常。


要在闡述什麼評論者說,斷言之間的差,假設和要求是:

  • 甲Contract.Assert表達式被轉換成由所述合同重寫和靜態分析器的斷言試圖根據其現有證據來證明這一表達。如果它不能被證明,你會得到一個靜態分析警告。
  • Contract.Assume表達式被合約重寫器忽略(據我所知),但被靜態分析器解釋爲它在靜態分析中可以考慮的新證據。合同。假設習慣於在靜態分析中「填補空白」,無論是缺乏進行必要推理的複雜性還是與尚未用合同進行過修飾的代碼進行交互操作時,都可以假設,例如,一個特定的函數調用返回一個非空結果。
  • Contract.Requires是調用方法時必須始終爲真的條件。它們可以是對方法參數的約束(這是最典型的),它們也可能是對象的公開可見狀態的約束(例如,如果Initialized爲True,則只允許調用該方法)。這些類型的約束推動你的類的用戶在使用對象時檢查初始化(如果不是,則可能會適當地處理錯誤),或者創建他們自己的約束和/或類不變量來澄清初始化確實發生了。
+0

那麼......那麼Contract'Assert'和'Contract.Requires'之間的區別究竟是什麼? – mpen 2010-12-15 03:05:34

+2

@Ralph:'Contract.Requires'表示在調用該方法時應該爲true的事物,'Contract.Assert'應該在您的方法中間檢查中間狀態。在正確的位置添加'Contract.Assert'可以幫助靜態分析器驗證您的代碼是否正確,如果它無法自行管理的話。 – 2010-12-15 03:18:28

+3

實際上,靜態檢查器只會從Contract.Assume中受益。此方法在運行時的行爲與Contract.Assert相似,但告訴靜態檢查器不要試圖統計證明這一點。 – koenmetsu 2010-12-15 07:53:50

2

第一種方法適用於測試不應存在的空條件。也就是說,在開發過程中使用它來確保它不會意外地被設置爲null。由於它不做任何錯誤處理,因此這不適用於處理髮布產品中的空條件。

我會說第二和第三個版本是相似的,他們不以任何方式處理這個問題。

通常,如果變量在最終產品中可能實際上爲空,則最後一個版本是可以使用的版本。你可以在那裏做特殊的處理,或者像你一樣引發異常。

+1

實際上,第二個和第三個方法使用靜態分析來試圖在編譯時證明它們是真實的。 – 2010-12-15 01:33:24

+0

@Anon:但是靜態分析器將無法在編譯時捕獲所有空例外......如果一個人滑倒,會發生什麼?它是否會引發異常,崩潰,什麼都不做或什麼? – mpen 2010-12-15 03:03:55

+1

@Ralph:如果靜態分析器無法證明任何方式(它不能證明合約在某些情況下會失敗,但它不能證明它總是正確的),它會顯示編譯警告(不是錯誤)並將其替換爲斷言。 – 2010-12-15 03:19:09