【问题标题】:Can/Should you throw exceptions in a c# switch statement?你可以/应该在 c# switch 语句中抛出异常吗?
【发布时间】:2011-02-11 04:57:59
【问题描述】:

我有一个返回 int 的插入查询。基于该 int 我可能希望抛出一个异常。这适合在 switch 语句中执行吗?

 switch (result)
        {

            case D_USER_NOT_FOUND:
                throw new ClientException(string.Format("D User Name: {0} , was not found.", dTbx.Text));
            case C_USER_NOT_FOUND:
                throw new ClientException(string.Format("C User Name: {0} , was not found.", cTbx.Text));
            case D_USER_ALREADY_MAPPED:
                throw new ClientException(string.Format("D User Name: {0} , is already mapped.", dTbx.Text));
            case C_USER_ALREADY_MAPPED:
                throw new ClientException(string.Format("C User Name: {0} , is already mapped.", cTbx.Text));
            default:

                break;
        }

我通常会在开关中添加 break 语句,但它们不会被击中。这是一个糟糕的设计吗?请与我分享任何意见/建议。

谢谢, ~ck 在圣地亚哥

【问题讨论】:

  • 看起来您正在尝试将返回码映射到异常。你的意图很明确,所以我会说这个解决方案很好。

标签: c# exception switch-statement throw


【解决方案1】:

我不太同意您的变量命名约定 ;),但我不明白为什么您所做的不合适。这似乎是一种将错误从一种媒介转换为另一种媒介的相当优雅的方式。

我假设您的“插入查询”是某种形式的存储过程。

【讨论】:

    【解决方案2】:

    我认为这没问题。似乎您正在使用 switch 语句将返回码映射到异常。只要没有太多的情况,这不是问题。

    【讨论】:

      【解决方案3】:

      如果可能的话,如果你在设置失败结果的地方投掷可能会更好,否则你最终不得不同时进行结果检查和投掷。但当然不可能。

      另外,我会将您的错误字符串转换为带有占位符的资源或常量,这样如果您想更改措辞,就不必更改多个位置。

      【讨论】:

        【解决方案4】:

        没问题...为什么这是糟糕的设计?

        另外,由于所有cases 中的异常类型都相同,您可以为错误消息构造一个查找表。这将为您节省一些代码重复。例如:

        static private Dictionary<int, string> errorMessages;
        static
        {
            // create and fill the Dictionary
        }
        
        // meanwhile, elsewhere in the code...
        if (result is not ok) {
            throw new ClientException(string.Format(errorMessages[result], cTbx.Text, dTbx.Text));
        }
        

        在消息本身中,您可以使用{0}{1} 等选择适当的参数。

        【讨论】:

          【解决方案5】:

          您采用的方法没有任何问题。 Switch 语句比 if/then 语句更容易阅读(也可能更快)。您可以做的另一件事是在

          中加载可能的异常
          Dictionary<Result_Type, Exception>
          

          并从那里拉出异常。如果你有很多 switch 语句,这会使代码更紧凑(如果需要,你可以在运行时添加和删除它们)。

          【讨论】:

          • 字典可能很好,但它必须是 Dictionary&lt;Result_Type, Func&lt;Exception&gt;Dictionary&lt;Result_Type, ExceptionFactory&gt;Dictionary&lt;Result_Type, IExceptionFactory&gt; 之类的,具有适当定义的异常工厂类(和接口,如果适用)在某处定义。抛出一个现有的异常对象至少会破坏堆栈跟踪。如果两个线程同时遇到相同类型的异常,在它们之间共享一个异常对象可能会导致一个线程的处理程序看到另一个线程的堆栈跟踪。
          • 是的,这不是使用字典的最佳示例。如果有什么你可能需要存储异常类型,而不是实际的异常本身。
          • 不幸的是,存储异常类型并没有多大用处,因为除非使用反射(在异常的上下文中有点狡猾的介词),否则没有通用的方法,给定异常类型,生成该类型的异常。
          【解决方案6】:

          为什么不呢?

          来自 Anders Hejlsberg 等人的 The C# Programming Language, Third Ed.,第 362 页:

          switch 部分的语句列表通常以breakgoto casegoto default 语句结尾,但任何使语句列表的端点无法到达的构造都是允许的。 [...] 同样,throwreturn 语句总是将控制权转移到别处,并且永远不会到达终点。因此下面的例子是有效的:

          switch(i) {
          case 0:
              while(true) F();
          case 1:
              throw new ArgumentException();
          case 2:
              return;
          }
          

          【讨论】:

            【解决方案7】:

            我认为在您的情况下使用开关没有任何问题。

            更强烈的考虑应该是例外本身是否合适。通常,仅当出现超出预期行为范围的情况时才应使用异常。不应将异常用作程序流逻辑。在您的情况下,根据我看到的代码,您可能可以使用它们。

            【讨论】:

              【解决方案8】:

              也许我希望与这里的所有答案有所不同..

              与其切换代码,我宁愿将result 传递给ClientException 类并让它决定它需要显示的字符串,而不是到处都有一个丑陋的开关来创建各种消息

              我的代码如下所示:

              throw new ClientException(result, cTbx.Text);
              

              所以,即使你可以在switch...case 中抛出错误,你也可以避免这一切都是我的选择

              【讨论】:

              • 此时 ClientException 构造函数将具有相同的切换逻辑,但必须有中断。
              • 我投了反对票,因为这个“解决方案”只是改变了问题。这并没有什么真正的区别。
              • @Seventh Element - 你说得对,没有产生任何真正的区别,但在我的解决方案中,代码更易于维护,因为 switch...case 位于 ClientException 类中并且调用者需要不要在他们的代码中一遍又一遍地编写 switch...case...
              • 除了@Yishai 提出的观点之外,结果可能并不总是错误代码。
              • @Rowland - 在您提到的情况下,是否会出现重载: throw new ClientException("message");帮助?我已经看到 Exception 类有各种重载的构造函数,我认为这样做是一个好习惯......
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-05-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-12-15
              相关资源
              最近更新 更多