.NET Framework有许多预定义的异常。例如,如果将无效参数传递给我的方法,我应该引发ArgumentException
(或ArgumentNullException
,如果参数为null
)。如果调用的方法对当前对象状态无效,我应该引发InvalidOperationException
。
是否存在“永远不应该访问此代码”案例的预定义异常?这是一个例子:
void myMethod() {
int a;
... /* Some complex code that manipulates a. In the end, "a" can only be 1 or 2. */
switch (a) {
case 1: ...
case 2: ...
default: // just an extra sanity check
// Oops, we should never be here.
// There's apparently some bug in the code above.
throw new ThereIsABugInTheCodeException();
}
}
我不认为为这种罕见案件创建我自己的例外是合理的。另一方面,只是抛出Exception
is discouraged as well。我想某种AssertionFailedException
是合适的,但我没有在.net框架中找到任何内容。 (请注意,Trace.Assert不会抛出异常,所以这也不是一个选项。)
编辑:澄清一下:a
不是一个参数。让我重新解释一下这个问题,使其更加清晰:在方法的中间,我会进行健全性检查(只是为了确保,如果方法开头的代码是正确的,那么就没有必要)。我发现理智检查失败了,并想抛出异常。我要扔哪一个?我不认为ArgumentException
是正确答案,因为ArgumentException
should only be thrown if the caller of the method did something wrong。这里情况不同。 方法本身在运行时意识到它包含一个错误。
答案 0 :(得分:4)
奇怪的是,.NET Framework不包含描述逻辑错误或内部错误的异常。但另一方面,.NET Framework应该具有质量级别,不应该为内部错误抛出异常。您是否相信在文档中声明它可能会抛出InternalErrorException
的.NET API调用?请记住,从SystemException
派生的异常是框架使用的异常。重用这些异常非常有用,但创建了异常以供框架而不是框架/应用程序使用。
如果您的方法以意外方式调用,则可以使用ArgumentException
,ArgumentNullException
,ArgumentOufOfRangeException
,NotSupportedException
和InvalidOperationException
。
您还可以创建自己的InternalErrorException
。
微软更常见的解决方案是Code Contracts。可以在编译时检查许多合同,帮助您生成更好的代码,并且可以使用Contract.Assume
和Contract.Assert
来验证代码中的条件。如果条件为false,重写器将插入将抛出ContractException
的代码。此异常是以特殊方式制作的(来自DevLabs Code Contracts documentation):
ContractException类型不是公共类型,并作为嵌套的私有类型发布到为其启用运行时协定检查的每个程序集中。因此,不可能编写仅捕获ContractException的catch处理程序。因此,合同例外只能作为一般异常支持的一部分来处理。这种设计的基本原理是程序不应包含依赖于合同失败的控制逻辑,就像程序不应该捕获ArgumentNullException或类似的验证异常一样。
答案 1 :(得分:3)
对于您展示的情况,我也会使用ArgumentException
,可能是ArgumentOutOfRangeException
。
编辑我没有仔细观察,虽然switch
是关于方法参数的,但显然不是。所以ArgumentException
可能不适用。我答案的其余部分就是这样。
然而,确实存在程序状态完全出乎意料的情况。对于这种情况,我甚至不会使用异常(可以捕获)。在这种情况下,人们可能会争辩说,安全性和数据完整性受到威胁,因此唯一明智的做法是尽快退出应用程序(以最大限度地减少破坏状态的可能性)。
在这种情况下,你应该考虑使用Debug.Assert
或Trace.Assert
,或者推送一个本质上调用Environment.FailFast
的处理程序。
这种行为对于您的应用程序是否正确或可接受是您必须做出的决定。
更新:您可能还想查看Code Contracts。哪个AFAIK可以在其运行时行为中进行定制,以抛出异常,中止该过程或不执行任何操作。
答案 2 :(得分:2)
在这种情况下,我会使用ArgumentException
。
您的a
参数会出现意外值。
throw new ArgumentException(string.Format("Unexpected value {0} for a.", a);
虽然取决于具体情况,ArgumentOutOfRangeException可能更合适,如@ todda.speot.is所评论。
答案 3 :(得分:1)
我建议定义并抛出一个自定义异常类型,这些异常类型本质上会识别出现问题条件的应用程序层。我还建议捕获许多类型的异常,这些异常表示逻辑或状态相关的问题,并重新抛出为自定义类型。否则,如果某人调用您的方法并向其发出ArgumentException
,则调用者将不知道这是否是他将无效参数传递给您的代码,或者它是否表示您的代码存在内部问题。请注意,由于函数内联之类的东西,StackTrace可能不会列出调用链中涉及的所有方法。
答案 4 :(得分:0)
您确定存在“错误异常”概念吗?
在您的示例中,如果ArgumentOutOfRangeException
是参数,则肯定是a
例外。
如果你的代码试图执行一些永远不应该被执行的代码,那么我认为比“嘿!Bug here!”更需要的东西需要被抛出上游。
答案 5 :(得分:0)
ThisIsABugException在概念上是不正确的。
如果你的方法的合同被传递(参数是正确的,所以没有ArgumentExceptions),你的方法在技术上不应该失败。如果所有参数都正确且方法本身的逻辑是正确的,为什么要这样做呢?
因此,当您检查方法契约(参数)时,会引发ArgumentException或其子代。
如果在你的方法中你称某些东西不可靠并且收到一些奇怪的结果,那么你可能会提出一些有意义的东西而不是失败的“哦,bug!bug!”。确实是bug,那又怎样?我宁愿在操作的背景下提出一些有意义的东西。
如果由于您的业务规则而必须抛出,请说您被要求停用帐户,并且参数正确,但在该方法中您发现此帐户已处于非活动状态,这确实是无效操作,然后InvalidOperationException会这样做,这就是我们在.NET中有这个“泛型”异常的原因。
这就是为什么你永远不想提出ThisIsABugException或类似的东西。