簡體   English   中英

為什么我們不拋出這些異常?

[英]Why are we not to throw these exceptions?

我遇到了這個 MSDN 頁面,上面寫着:

不要故意從您自己的源代碼中拋出ExceptionSystemExceptionNullReferenceExceptionIndexOutOfRangeException

不幸的是,它沒有費心解釋原因。 我可以猜測原因,但我希望在這個主題上更權威的人可以提供他們的見解。

前兩個有一些明顯的意義,但后兩個似乎是你想要使用的(事實上,我有)。

此外,這些是唯一應該避免的例外嗎? 如果還有其他人,他們是什么,為什么也應該避免?

Exception是所有異常的基本類型,因此非常不具體。 你永遠不應該拋出這個異常,因為它根本不包含任何有用的信息。 調用代碼捕獲異常無法消除有意拋出的異常(來自您的邏輯)與其他完全不需要的系統異常並指出真正的錯誤。

同樣的原因也適用於SystemException 如果您查看派生類型列表,您會看到大量其他語義非常不同的異常。

NullReferenceExceptionIndexOutOfRangeException屬於不同類型。 現在這些是非常具體的異常,所以拋出它們可能沒問題 但是,您仍然不想拋出這些,因為它們通常意味着您的邏輯中存在一些實際錯誤。 例如,空引用異常意味着您正在嘗試訪問null對象的成員。 如果這在您的代碼中是可能的,那么您應該始終明確檢查null並拋出更有用的異常(例如ArgumentNullException )。 類似地,當您訪問無效索引(在數組上,而不是列表上)時,會發生IndexOutOfRangeException 您應該始終確保首先不要這樣做,並首先檢查例如數組的邊界。

還有一些其他異常,例如這兩個異常,例如InvalidCastExceptionDivideByZeroException ,它們是針對代碼中的特定錯誤而引發的,通常意味着您做錯了什么或沒有先檢查某些無效值。 通過故意從代碼中拋出它們,您只會讓調用代碼更難確定它們是由於代碼中的某些錯誤而被拋出,還是僅僅因為您決定在實現中重用它們。

當然,這些規則也有一些例外(哈哈)。 如果您正在構建可能導致與現有異常完全匹配的異常的東西,那么請隨意使用它,尤其是當您嘗試匹配某些內置行為時。 只需確保您選擇了一個非常具體的異常類型。

但總的來說,除非您找到滿足您需求的(特定)異常,否則您應該始終考慮為特定的預期異常創建自己的異常類型。 尤其是在編寫庫代碼時,這對於分離異常源非常有用。

我懷疑最后 2 個的目的是防止與具有預期含義的內置異常混淆。 但是,我認為,如果您保留異常的確切意圖throw是正確的。 例如,如果您正在編寫自定義集合,則使用IndexOutOfRangeException似乎是完全合理的 - IMO 比ArgumentOutOfRangeException更清晰、更具體。 雖然List<T>可能會選擇后者,但 BCL中至少有41 個地方(由反射器提供)(不包括數組)會拋出定制的IndexOutOfRangeException - 其中沒有一個是“低級”的,值得特別豁免。 所以,是的,我認為您可以辯稱該指南很愚蠢。 同樣, NullReferenceException在擴展方法中很有用 - 如果您想保留以下語義:

obj.SomeMethod(); // this is actually an extension method

objnull時拋出NullReferenceException

正如您所指出的,在“拋出異常時要避免的事情”主題下的創建和拋出異常(C# 編程指南)一文中,Microsoft 確實將System.IndexOutOfRangeException列為不應從您自己的源代碼中有意拋出的異常類型。

然而,相比之下,在文章throw (C# Reference) 中,微軟似乎違反了自己的指導方針。 這是微軟在其示例中包含的一種方法:

static int GetNumber(int index)
{
    int[] nums = { 300, 600, 900 };
    if (index > nums.Length)
    {
        throw new IndexOutOfRangeException();
    }
    return nums[index];
}

因此,Microsoft 本身並不一致,因為它在其throw文檔中演示了IndexOutOfRangeExceptionthrow

這讓我相信,至少對於IndexOutOfRangeException的情況,在某些情況下,程序員可能會拋出該異常類型並被認為是可接受的做法。

當我讀到你的問題時,我問自己在什么條件下會想要拋出異常類型NullReferenceExceptionInvalidCastExceptionArgumentOutOfRangeException

在我看來,當遇到其中一種異常類型時,我(開發人員)對編譯器正在與我交談的警告感到擔憂。 所以,允許你(開發者)拋出這樣的異常類型就相當於(編譯器)賣掉了責任。 例如,這表明編譯器現在應該允許開發人員決定一個對象是否為null 但是做出這樣的決定確實應該是編譯器的工作。

PS:自 2003 年以來,我一直在開發自己的異常,以便我可以隨心所欲地拋出它們。 我認為這樣做被認為是最佳實踐。

把關於NullReferenceExceptionIndexOutOfBoundsException的討論放在一邊:

捕獲和拋出System.Exception怎么樣。 我在我的代碼中拋出了很多這種類型的異常,我從來沒有被它搞砸過。 同樣,我經常捕捉到非特定的Exception類型,它對我來說也很有效。 那么,這是為什么呢?

通常用戶會爭辯說,他們應該能夠區分錯誤原因。 根據我的經驗,在極少數情況下,您希望以不同的方式處理不同的異常類型。 對於那些希望用戶以編程方式處理錯誤的情況,您應該拋出更具體的異常類型。 對於其他情況,我不相信一般的最佳實踐指南。

所以,關於拋出Exception我沒有看到在所有情況下都禁止這樣做的理由。

編輯:也來自 MSDN 頁面:

作為普通執行的一部分,不應使用異常來更改程序的流程。 異常應該只用於報告和處理錯誤情況。

對不同的異常類型使用單獨的邏輯過度使用 catch 子句也不是最佳實踐。

暫無
暫無

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

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