2010-07-22 20 views
16

當程序達到我「知道」不會發生的邏輯狀態時,應該使用哪種例外情況,如果情況確實如此,那麼情況會非常糟糕。我的程序中應該拋出哪些異常來表示內部錯誤?

例如:

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的值無效能夠在不管(),或任何參數組合無效和/或都來自一個bug當前實例狀態。

我正在尋找諸如InvalidProgramStateException,InternalErrorException或類似的東西。

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

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

+1

爲什麼不使用您已經建議的名稱創建自己的異常?或者'ShouldNotHappenException'怎麼樣? ;-) – 2010-07-22 22:21:55

+2

@ 0xA3這不算最佳做法 – 2010-07-22 23:09:47

+2

@erik:這裏沒有內部錯誤。您在傳遞給您的方法的參數中有錯誤。這可能相當於全局意義上的內部錯誤,但是您在本地級別上具有的是「ArgumentOutOfRangeException」,正如下面所述的「chibacity」所示。 – 2010-07-22 23:13:37

回答

4

InvalidOperationException呢?

+5

我有時會使用那個,但我認爲這個例外說「你不能這樣做」,我想說的是「你應該能夠做到這一點,但有一個錯誤」。 – erikkallen 2010-07-22 22:13:34

+0

從[MSDN](https://msdn.microsoft.com/en-us/library/system.invalidoperationexception%28v=vs.110%29.aspx):「InvalidOperationException用於調用方法失敗的情況是由無效論點以外的原因引起的。「所以,我的投票是這個選擇。 – fernio 2015-05-06 21:07:42

+1

@erikkallen,也許是NotImplementedException? – Fred 2015-09-03 15:12:16

2

我覺得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); 
    } 
} 

顯然,該消息是自己的口味,但基本是在那一個。將enum的值添加到消息中不僅有助於詳細說明哪些已知的枚舉成員沒有處理,而且還存在無效的枚舉,即舊的「(666)SomeEnum」問題。

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

VS

值 '666' 的枚舉 'SomeEnum' 沒有被處理。

+2

如果切換的值不是參數,該怎麼辦? 順便說一句,我刪除了答案很可能是ArgumentException的簡單示例。 – erikkallen 2010-07-23 08:55:36

+2

@erikkallen該值是switch語句的一個參數,正如我在回答中所述。 – 2010-07-23 11:14:06

1

這裏是我一直在考慮建議:

  • ArgumentException:什麼是錯與價值

  • ArgumentNullException:雖然這是不允許的參數爲空

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

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

輸入是無效如果它在任何時候都無效。雖然輸入是意想不到的如果它不適用於系統的當前狀態(在某些情況下InvalidOperationException是合理的選擇)。

See similar question and answer that I was given.

+1

問題的關鍵在於無效狀態與參數無關。我同意,在簡單的情況下,ArgumentException可以做,但我不認爲應該使用ArgumentException作爲泛型「oops,沒有工作,我敢打賭它必須做的參數」異常。 – erikkallen 2010-07-23 08:54:57

+0

switch語句是超出範圍的參數。 – 2010-07-23 17:34:27

0

「程序到達邏輯狀態,我‘知道’不會發生,如果是這樣,什麼是差得要命。」

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

+3

我不認爲這是一個好主意。 ApplicationException(在它不贊成使用之前)的最初目的是應用程序拋出的任何(預期的)異常應該從它派生。 – erikkallen 2010-07-23 08:53:24

1

您應該考慮使用代碼合約來在這種情況下不僅引發異常,而且記錄失敗的假設是什麼,可能是給程序員一個友好的消息。如果你幸運的話,你所調用的函數(Whatever)將會有一個Contract.Ensures,在你接手之前就會發現這個錯誤。

4

爲什麼不是InvalidEnumArgumentException?它看起來就是專門爲這個用例設計的。

2

不要在您正在查看的代碼中拋出任何特定的異常類型。請撥打Trace.Assert,否則在此情況下甚至可以使用Trace.Fail以獲得與Debug.Assert類似的效果,即使在發佈版本中(假設設置未更改)也可以啓用。

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

異常類型應該是一個私有異常類型,因爲否則,調用者可能會試圖捕獲您要拋出的異常類型。對於這種特殊的異常類型,您將希望儘可能清楚該方法的未來版本將不再拋出此特定異常。你不希望被迫拋出一個TraceFailedException或者從現在開始直到永恆,以保持向後兼容性。


提到的另一個答案代碼合同已經作爲替代。它以類似的方式:您可以撥打Contract.Assert(false)。這採用了相同的方法來使其可定製如果斷言失敗會發生什麼情況,但在這種情況下,默認行爲是拋出一個異常,該異常又是一種不可從外部訪問的類型。然而,爲了充分利用代碼合約,你應該使用靜態重寫器,它既有優點也有缺點,我不會在這裏討論。如果你的專家勝過弊,那麼一定要用它。如果你更喜歡避免使用靜態重寫器,那麼我建議完全避免Contract類,因爲很明顯哪些方法不起作用。

相關問題