簡體   English   中英

我應該拋出哪個異常來表示程序中的內部錯誤?

[英]Which Exception Should I Throw to Signal an Internal Error in my Program?

當程序達到我“知道”不會發生的邏輯狀態時,我應該使用哪個異常,如果它發生了,那么事情非常糟糕?

例如:

int SomeFunction(int arg) {
    SomeEnum x = Whatever(arg, somePrivateMember);
    switch (x) {
        case SomeEnum.Value1:
            return SomeFunction1();
        case SomeEnum.Value1:
            return SomeFunction2();
        default:
            throw new WhatTypeToThrow();
    }
}

顯然,這里的 ArgumentException 是一個長鏡頭,因為 x 的無效值可能來自 What() 中的錯誤,或者任何參數和/或當前實例狀態的無效組合。

我正在尋找諸如 InvalidProgramStateException、InternalErrorException 之類的東西。

當然我可以自己定義,但是我想知道框架中是否有合適的例外。

編輯:刪除了簡單的示例代碼以減少 ArgumentException 答案的數量。

InvalidOperationException 呢?

為什么不是 InvalidEnumArgumentException? 看起來它是專門為這個用例設計的。

不要在您正在查看的代碼中拋出任何特定的異常類型。 調用Trace.Assert ,或者在這種情況下甚至Trace.Fail以獲得與Debug.Assert類似的效果,除了在發布版本中啟用(假設設置未更改)。

如果默認跟蹤偵聽器(提供可Trace.Listeners整個程序或啟動調試器的 UI)不適合您的需要,請在Trace.Listeners中設置自定義跟蹤偵聽器,從而導致私有異常類型為每當Trace.Fail時拋出(包括當Trace.Assert失敗時)。

異常類型應該是私有異常類型,否則,調用者可能會試圖捕獲您要拋出的任何異常類型。 對於此特定異常類型,您將希望盡可能明確該方法的未來版本將不再拋出此特定異常。 您不想被迫拋出TraceFailedException或從現在到永遠的任何您稱之為它的東西,以保持向后兼容性。


另一個答案提到 Code Contracts 已經作為替代方案。 以類似的方式:您可以調用Contract.Assert(false) 這采用了相同的方法來定制斷言失敗時發生的情況,但在這種情況下,默認行為是拋出異常,同樣是外部無法訪問的類型。 然而,為了充分利用代碼契約,您應該使用靜態重寫器,它既有優點也有缺點,我不會在這里介紹。 如果對您來說利大於弊,那么一定要使用它。 如果您更喜歡避免使用靜態重寫器,那么我建議您完全避免使用Contract類,因為根本不清楚哪些方法起作用和不起作用。

我認為 ArgumentOutOfRangeException 在這里是有效的,這就是我使用的。 由於超出了處理值的范圍,因此不會處理 switch 語句的參數。 我傾向於這樣編碼,消息告訴它就像這樣:

switch (test)
{
    case SomeEnum.Woo:
        break;
    case SomeEnum.Yay:
        break;
    default:
    {
        string msg = string.Format("Value '{0}' for enum '{1}' is not handled.", 
            test, test.GetType().Name);

        throw new ArgumentOutOfRangeException(msg);
    }
}

顯然,該信息符合您自己的口味,但基礎知識就在其中。 將枚舉的值添加到消息中不僅可以提供有關未處理的已知枚舉成員的詳細信息,而且在存在無效枚舉(即舊的“(666)SomeEnum”問題)時也很有用。

不處理枚舉 'SomeEnum' 的值 'OhNoes'。

對比

不處理枚舉 'SomeEnum' 的值 '666'。

以下是我得到的建議:

  • ArgumentException : 值有問題

  • ArgumentNullException : 參數為空,而這是不允許的

  • ArgumentOutOfRangeException : 參數的值超出了有效范圍

或者,從ArgumentException派生您自己的異常類。

如果輸入在任何時候都無效,則輸入無效 如果輸入對系統的當前狀態無效,則輸入是意外的(在某些情況下InvalidOperationException是合理的選擇)。

請參閱我得到的類似問題和答案。

在這種情況下,您應該考慮使用代碼契約不僅拋出異常,而且記錄失敗的假設是什么,也許向程序員提供友好的消息。 如果你很幸運,你調用的函數( Whatever )會有一個Contract.Ensures ,它會在你得到它之前捕獲這個錯誤。

程序達到了我“知道”不會發生的邏輯狀態,如果發生了,事情就非常糟糕了。

在這種情況下,我會拋出一個 ApplicationException,記錄你能記錄的內容,然后退出應用程序。 如果事情搞砸了,您當然不應該嘗試恢復和/或繼續。

暫無
暫無

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

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