繁体   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