2009-09-22 107 views
8

有沒有之間的任何行爲差異:拋出新的異常VS Catch塊

if (s == null) // s is a string 
{ 
throw new NullReferenceException(); 
} 

和:

try 
{ 
    Console.Writeline(s); 
} 


catch (NullReferenceException Ex) 
{ // logic in here 
} 

空對象的兩個拋出異常,如果s爲null。第一個示例更具可讀性,因爲它顯示錯誤發生的位置(異常位恰好位於會引起異常的行的旁邊)。

我已經在各種博客上看到了各種各樣的技能水平的各種編碼器的編碼風格,但爲什麼不通過檢查s是否爲空來執行主邏輯,從而保存了曾經引發的異常?這種方法有缺點嗎?

謝謝

+1

+1好問題 – 2009-09-22 22:15:29

回答

18

不,Console.WriteLine(null)不會引發異常。它不會打印出任何東西。現在假設你的意思是這樣的:

Console.WriteLine(s.Length); 

那麼它是有道理的......你應該使用第一種形式。當您無法提前預測它們的當前信息時,就會發生例外情況。如果你可以很容易地發現問題出在哪裏,那麼嘗試一種必然會失敗的操作是沒有意義的。它導致代碼更難理解,並且性能更差。

所以NullReferenceException,ArgumentNullException之類的東西不應該被發現,除非它們是由於nasty API which sometimes throws exceptions which you can handle, but which shouldn't really be being thrown in the first place。這就是爲什麼在代碼契約,對於失敗的合同的默認行爲是拋出一個異常,你不能抓明確,不是通過捕捉一切(通常是在某處的堆棧的頂部)等。

+0

謝謝。我的意思是使用變量的任何情況(在方法/ ctor中),但是會導致NullReferenceException或對象引用未設置爲對象錯誤的實例。有一個編碼的朋友告訴我,第一種形式應該用於主叫方能夠捕獲異常的位置。所以,如果我有另一種方法調用第一個窗體併爲拋出的異常行添加catch塊。你會同意嗎? – dotnetdev 2009-09-22 22:18:48

+0

什麼,如果有的話,對象引用沒有設置爲對象的實例和NRE之間的關係? – dotnetdev 2009-09-22 22:20:59

+0

你怎麼知道這個異常是否會被調用者捕獲? 當出現錯誤(這是更多的信息),並讓.NET框架拋出一個通用的NullRef異常時,顯式拋出異常之間有什麼區別? – 2009-09-22 22:21:36

2

由於喬恩斯基特已經提到,Console.WriteLine (null)不會拋出異常。

下一步,我想說的是,你應該「快速失敗」。這意味着你必須在你的方法中加入'guard'子句,並且檢查你的方法中給出的參數是否可以被認爲是有效的。 這允許你自己拋出一個異常,並給出一個額外的消息,這在調試時會很有幫助。該消息可以明確指出哪些是錯誤的,如果您遇到在其消息屬性中沒有任何良好信息的情況下拋出NullReferenceException,那麼這會更加容易。

0

如果你正在做一項契約式設計型的方法來的東西,然後一段代碼可以指定它拋出異常,以指定其合同,並強制執行。另一半當然是調用識別合同並履行合同的代碼。

在這種情況下,這將意味着,如果你知道,如果你在空傳遞的方法將拋出一個異常(即與其簽訂合約的是,你不及格空),那麼你應該在調用它之前檢查。

Jon Skeet說這個方法不會拋出異常。這可能會也可能不會是真實的,但方法合同的守衛原則(我相信這是您的問題的重點)。

1

如果你正在寫一個類庫可能還有機會,當你知道,如果某個參數包含空值,這可能進一步造成麻煩的路線。在這些情況下,我通常會發現拋出一個異常是個好主意(儘管我可能會使用ArgumentNullException),以使類庫的用戶儘早清楚地意識到這一點。

異常並不總是一件壞事。

1

喬恩Skeet是正確的,但更一般地說,這都是一個語義問題。

如果情況有一些適用的含義(出界數量,未來出生日期等),您可能需要在做任何操作之前測試它並拋出一個自定義異常(這與您的意義有關應用)。

如果情況確實是「特殊」,只需將代碼編寫爲給定值是正確的。看,如果你進行測試,你會每次都這樣做,因爲知道虛擬機無論如何都會這樣做,以防它需要拋出異常。從性能角度來看,如果錯誤發生在統計上很少發生,那就沒有意義了。