【问题标题】:Correct exception to throw for an unhandled switch case for an argument?为参数的未处理开关情况抛出正确的异常?
【发布时间】:2012-11-30 11:53:34
【问题描述】:

注意:这与建议的重复项不同,因为它处理的是参数而不是值。行为和适用场景有本质的不同。

假设我们有 SomeEnum 并有一个 switch 语句来处理它:

enum SomeEnum
{
    One,
    Two,
}

void someFunc(SomeEnum value)
{
    switch(value)
    {
        case SomeEnum.One:
            ...
            break;
        case SomeEnum.Two:
            ... 
            break;
        default:
            throw new ??????Exception("Unhandled value: " + value.ToString());    
    }
}

如您所见,我们处理所有可能的枚举值,但仍保留默认值,以防添加新成员时抛出异常,并且我们希望确保我们知道缺少处理。

我的问题是:在您想要通知给定代码路径未处理/实现或不应该访问的情况下,正确的例外是什么?我们曾经使用NotImplementedException,但它似乎并不合适。我们的下一个候选人是InvalidOperationException,但这个词听起来不太对。什么是正确的,为什么?

编辑:C# 8.0 引入了switch expressions,它会为非详尽的 switch 语句生成编译器警告。这就是为什么您应该在适用的情况下使用 switch 表达式而不是 switch 语句的另一个原因。可以用更安全的方式编写相同的函数,例如:

void someFunc(SomeEnum value)
{
    _ = value switch
    {
        SomeEnum.One => ....,
        SomeEnum.Two => ...., 
    }
}

当一个新成员被添加到SomeEnum 时,编译器将显示警告 "CS8509: The switch expression does not handle all possible values of its input type (它不是穷举的)。例如,模式 'EnumHandling.SomeEnum.Three' 没有被覆盖。” 用于 switch 表达式,这样更容易捕捉潜在的错误。

【问题讨论】:

  • 致那些将其作为重复项关闭的人:您指出的问题 1) 是不同的情况(未处理的返回值不是参数,我有一个单独的问题)2)关于返回值。通过谴责此处给出的答案并将他们引导到错误的上下文和答案,您实际上是在伤害来这里的人。
  • @Habib 和其他密切投票者:这是怎么重复的?此问题特定于作为参数传入的 enum 值。另一个问题是关于不受支持的 switch case 的一般情况。这两个问题有不同的答案,有不同的推理。

标签: c# .net exception


【解决方案1】:

ArgumentException 在这种情况下对我来说是最正确的(尽管在 BCL 中没有定义)。

枚举参数有一个特殊的例外 - InvalidEnumArgumentException:

使用作为枚举数的无效参数时引发的异常。

另一种选择是ArgumentOutOfRangeException

当参数的值超出被调用方法定义的允许值范围时引发的异常。

使用这些的逻辑是传入的参数 (value) 就someFunc 而言是无效的。

【讨论】:

  • 你的意思是ArgumentExceptionInvalidArgumentException 用于 Sql-Server。
  • InvalidArgumentException 位于 Microsoft.SqlServer.Management.Common 命名空间中,几乎不适合一般情况 - 特别是因为它派生自 ConnectionException
  • “枚举有一个专门的版本 - InvalidEnumArgumentException:” - InvalidEnumArgumentException 不是 InvalidArgumentException 的专门版本(派生自)。
  • @ssg:我认为你应该问另一个问题,因为 IMO 它有另一个答案。
  • @ssg:关于未来的读者和一般的 SO 指南,我赞成:我对您的第一个问题(论点)的回答肯定是 InvalidEnumArgumentException,而我对另一个问题(内部值)肯定是InvalidOperationException
【解决方案2】:

我会抛出InvalidEnumArgumentException,因为它会在这种情况下提供更详细的信息,您正在检查一个枚举

【讨论】:

  • 由于差异可能很容易被过度解读,我特别想指出这个答案可能是比其他指向(更通用,更不具体)ArgumentException 的答案更好的解决方案.
  • @O.R.Mapper 谢谢我同意,越具体,您可以从异常中获得越详细的信息
  • @O.R.Mapper 我同意,但问题已结束。由于现在它再次打开,我选择这个作为接受的答案。谢谢@CR41G14!
【解决方案3】:

因为你有一个函数的登录,你可以抛出InvalidArgumentException

当参数无效时引发的异常是 传递给与服务器的引用连接上的方法

编辑: 更好的选择是:ArgumentException,因为 InvalidArgumentExceptionMicrosoft.SqlServer.Management.Common 命名空间中。比如:

throw new ArgumentException("Unhandled value: " + value.ToString());

【讨论】:

  • InvalidArgumentException 位于 Microsoft.SqlServer.Management.Common 命名空间中,几乎不适合一般情况 - 特别是因为它派生自 ConnectionException
  • @Joe,谢谢你,我在看到你之前的评论后正在编辑我的答案
【解决方案4】:

无效参数异常。 当用户传入一些无效值或需要value值时,建议处理InvalidArgumentException。

【讨论】:

    【解决方案5】:

    如果您使用的是代码契约(我强烈建议推荐),您可以将其放在方法的开头:

    Contract.Requires(value == SomeEnum.One || value == SomeEnum.Two);
    

    如果你想检查一个枚举的范围,它有太多单独的值而无法明确地写出来,你可以这样做:

    Contract.Requires(SomeEnum.One <= value && value <= SomeEnum.Two);
    

    【讨论】:

    • OP特指输入值定义,但方法不处理的情况。
    猜你喜欢
    • 2023-01-10
    • 2012-11-18
    • 1970-01-01
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多