.net 正确的异常引发一个未经处理的开关的情况下,一个参数?

yqkkidmi  于 2023-10-21  发布在  .NET
关注(0)|答案(6)|浏览(118)

假设我们有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,它会对非exahustive switch语句产生编译器警告。这也是为什么在适用的情况下应该使用switch表达式而不是switch语句的另一个原因。同样的函数可以用更安全的方式编写,比如:

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

当一个新成员被添加到SomeEnum时,编译器将显示警告 “CS 8509:开关表达式不处理其输入类型的所有可能值(它不是穷举的)。例如,模式'EnumHandling.SomeEnum.Three'不包括开关表达式的.",这使得捕获潜在的错误变得更容易。

olmpazwi

olmpazwi1#

ArgumentException在这个示例中看起来最正确(尽管在BCL中没有定义)。
枚举参数有一个特殊的例外-InvalidEnumArgumentException
使用作为枚举数的无效参数时引发的异常。
另一种选择是ArgumentOutOfRangeException
当参数的值超出被调用方法定义的允许值范围时引发的异常。
使用这些的逻辑是传入的参数(value)对于someFunc来说是无效的。

daupos2t

daupos2t2#

我会抛出InvalidEnumArgumentException,因为它将给予更详细的信息,在这种情况下,您正在检查枚举

0x6upsns

0x6upsns3#

因为你在函数中有登录名,你可以抛出InvalidArgumentException
当一个无效的参数被传递到服务器的引用连接上的方法**时引发的异常。

**编辑:**一个更好的选择是:ArgumentException,因为Microsoft.SqlServer.Management.Common命名空间中有InvalidArgumentException。例如:

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

nuypyhwy4#

InvalidArgumentException。当用户传递了一些无效的值或null值时,如果需要value,建议处理InvalidArgumentException。

roqulrg3

roqulrg35#

如果你正在使用Code Contracts(我强烈推荐),你应该把它放在方法的开头:

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

如果你想检查一个枚举的范围,该范围有太多的单独值而无法显式地写入它们,你可以这样做:

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

jucafojl6#

它们是接口的合约的一部分,所以这完全取决于你想要交流什么;什么是“意图”。我能想到三种不同的情况:
1.未处理的情况是一个 * 实现错误 *,也就是说,它应该被认为是一个bug,永远不会发生。
1.我从来没有打算支持这个案子。
1.未处理的情况下可以在实践中工作,但 * 目前不支持 *。
在前两种情况下,一个理想的API将 * 防止 * 异常发生。在第三种情况下,例外可能更适合作为维护更清晰的API的一种方式,这样可以更容易地发展。
更详细地考虑这三种情况:

  1. NotImplementedException很好地传达了这一点。但是,这不是您会提交到稳定分支或希望在生产代码中看到的东西。而且,作为一个一般的经验法则,只要语言特性可以帮助您避免编写异常,就使用它们。正如OP在编辑中指出的那样,C# 8.0's switch expressions服务于相同的目的。您将得到一个编译错误,而不是运行时错误。
    1.我个人更喜欢ArgumentException。但是,我也会考虑是否可以通过在类型系统中嵌入相同的信息来防止异常。例如,删除枚举值,或创建一个作为原始枚举子集的用途受限枚举。
  2. NotSupportedException通常用于更抽象的接口,但您(尚未)准备好为所有具体情况提供实现。请注意,这应被视为违反Liskov Substitution Principle;然而,如果有一个 * 意图 * 支持未来的实现,这可能是一个值得的权衡。
    作为结论,显然有些人使用ArgumentOutOfRangeException,也提到了by one of the existing answers。但是,这让我感到奇怪:
    文件中可能相关的唯一指示是:* “包含无效值,该值不是参数”*“所需的值集的成员。但是,(1)如果这是标准,那么基本上任何ArgumentException都可以被认为是范围异常,使类型毫无意义;和(2)类型名称中的“range”意味着 * 可比 * 值,这在语义上不是枚举。

相关问题