我应该抛出哪种异常来表示程序中的内部错误?

时间:2010-07-22 22:10:32

标签: c# .net exception

当程序达到我“知道”不会发生的逻辑状态时,我应该使用哪个异常,如果确实如此,那就非常糟糕了。

例如:

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的无效值可能来自Whatever()中的错误,或者是任何参数和/或当前实例状态的无效组合。

我正在寻找诸如InvalidProgramStateException,InternalErrorException或类似的东西。

当然我可以定义自己的,但我想知道框架中是否有合适的例外。

编辑:删除了简单的示例代码,以减少ArgumentException答案的数量。

7 个答案:

答案 0 :(得分:4)

InvalidOperationException怎么办?

答案 1 :(得分:4)

为什么不是InvalidEnumArgumentException?看起来它是专门为这个用例设计的。

答案 2 :(得分: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);
    }
}

显然,这条信息符合您自己的口味,但基本信息都在于此。将枚举的值添加到消息中不仅有助于详细说明未处理的已知枚举成员,还有无效的枚举,即旧的“(666)SomeEnum”问题。

  

枚举'SomeEnum'的值'OhNoes'未得到处理。

VS

  

未处理枚举'SomeEnum'的值'666'。

答案 3 :(得分:2)

不要在您正在查看的代码中抛出任何特定的异常类型。调用Trace.Assert,或者在这种情况下甚至是Trace.Fail,以获得与Debug.Assert类似的效果,除非在版本构建中启用(假设设置未更改)。

如果默认跟踪侦听器(提供用于终止整个程序或启动调试器的UI)不适合您的需要,请在Trace.Listeners中设置自定义跟踪侦听器,导致调用Trace.Fail时要抛出的私有异常类型(包括Trace.Assert失败时)。

异常类型应该是私有异常类型,否则调用者可能会尝试捕获您要抛出的任何异常类型。对于此特定异常类型,您将希望尽可能清楚地表明该方法的未来版本将不再抛出此特定异常。你不想被迫抛出一个TraceFailedException或你从现在开始直到永恒的任何东西,以保持向后兼容性。

另一个答案提到代码合同已经作为替代方案。它以类似的方式:你可以拨打Contract.Assert(false)。这采用了相同的方法使其可自定义如果断言失败会发生什么,但在这种情况下,默认行为是抛出异常,同样是一种无法从外部访问的类型。但是,为了充分利用代码合约,你应该使用静态重写器,它既有利也有弊,我不会在这里讨论。如果你的利益超过缺点,那么一定要使用它。如果您更愿意避免使用静态重写器,那么我建议完全避免使用Contract类,因为哪些方法不起作用并且不起作用。

答案 4 :(得分:1)

以下是我给出的建议:

  • ArgumentException:值

  • 出错
  • ArgumentNullException:参数为null,但不允许这样做

  • ArgumentOutOfRangeException:参数的值超出有效范围

或者,从ArgumentException派生自己的异常类。

输入无效,如果它在任何时候无效。如果输入意外,如果它对系统的当前状态无效(在某些情况下InvalidOperationException是合理的选择)。

See similar question and answer that I was given.

答案 5 :(得分:1)

您应该考虑使用代码约定来不仅在这种情况下抛出异常,而是记录失败的假设,也许是向程序员发出友好的消息。如果你很幸运,你调用的函数(Whatever)会有一个Contract.Ensures,它会在你接手之前发现这个错误。

答案 6 :(得分:0)

“程序达到逻辑状态,我”知道“不会发生,如果确实如此,那就非常糟糕。”

在这种情况下,我会抛出一个ApplicationException,记录你所能做的并退出应用程序。如果事情搞砸了,你当然不应该试图恢复和/或继续。