【问题标题】:C# Do exceptions IDs existC# 是否存在异常 ID
【发布时间】:2012-10-25 08:11:38
【问题描述】:

我的软件使用 Try Catch 来捕捉错误;最近发生了一个错误(与数据库的超时连接),并弹出 Messagebox.Show() 提醒用户该问题。这种内部软件的最终用户根本不具备 IT 知识。收到这条信息的女士问我她和谁失去了联系(我真的认为她认为这是一种精神上的“联系”,因为她看起来像一个嬉皮士)。

所以我想做的是简化错误消息。

我考虑过的事情:

我可以检查/比较 ex.Message 字符串与我想要满足的字符串列表,如果匹配,我将显示简化版本。国际海事组织,不现实。

然后我想有多个捕获,如果它是某种类型,则显示简单的消息。但是我的代码会有多混乱!不仅如此,它还可能以误导性消息告终,因为并非所有(例如)TimeOutExceptions 都是相同的。

或者,我必须尝试编写自己的异常类型来满足这一点。

然后,如果每个 .NET 异常都有一个关联的 ID,那将非常方便 - 这样,我可以用每个 ID 和我自己的好且易于准备/理解的消息编写一个很好的 case 语句。

之前有没有其他人考虑过这个问题,他们是否找到了合适的安排。还是只在屏幕上显示一条消息“错误 - 一封电子邮件已发送给软件供应商......”更好)?

【问题讨论】:

    标签: c# try-catch


    【解决方案1】:

    您不应该向最终用户显示 Exception.message。这是有助于识别错误类型的信息性文本。

    任何时候你捕捉到异常,你都应该正确处理它或重新抛出/抛出另一个。如果您处于通过显示一些错误消息来处理异常的代码点,您应该能够从异常本身正确推断上下文。您可以使用适当的异常类型来创建一些基本的异常域(DatabaseException、CommunicationException),并使用错误代码在其域内进一步区分异常。

    您可以使用属于 Exception 类的 IDictionary 类型的 Data 属性,从而用作 Exception 状态包。然后,您可以在此处存储类似 'ERR_CODE' = CONSTANT 的内容,并使用一些单点异常处理来检查错误代码,如果存在,则使用一些用户友好的输出来处理异常。

    您甚至可以在当前 AppDomain 中注册全局异常处理程序以捕获任何未捕获的异常并显示一些消息。这是常见的做法,但您必须意识到这种方法会破坏自然的代码流,如果发生这种情况,您将得到已处理的异常但未捕获的异常流(您没有在调用者站点上处理异常然后不知道调用失败并且行为可能无法预测)。因此,仅通过打印一些用户友好的消息并结束应用程序或终止当前用例来使用这种方法。

    【讨论】:

    • +1 这里面有一些很有意思的点和建议,谢谢
    【解决方案2】:

    如果曾经你写过catch (Exception ex)这样的代码,那么你做错了什么。您应该始终为异常的编码情况捕获特定的异常。

    阅读 Eric Lippert 的 "Vexing exceptions" blog entry

    捕获异常并仅显示消息属于“愚蠢”的异常类别。你永远不应该拥有它们。

    相反,您应该只使用 Eric 阐述的其他三种类型的例外。并且您应该捕获所涉及的特定异常类型,而不是通用的 Exception 类型。

    如果您捕获到特定异常,那么您可以向最终用户提供非常合理的信息 - 甚至提供有关如何解决问题的信息。

    更好的是,没有所有通用异常捕获您的代码将更容易调试、更清洁和更简洁。代码中错误的主要预测因素是您编写的实际代码行。少写代码,少bug。

    所以我的建议是更改您的代码设计并适当地处理异常。

    【讨论】:

    • 我同意你写的,但你的第一句话有点强 IMO;知道故障是致命的(根据 Eric 的博客)是否有用。例如,记录:catch(Exception ex) { Logging.Log(ex);扔前;您仍然认为最好避免 Exception ex 吗?还是您的意思只是在屏幕上显示消息?
    • 我经常使用 catch (Exception ex) 并且没有任何问题,只要我确保在此之前捕获更具体的错误。尤其是即使捕获到异常(System.Exception 类型),当我知道自己处于已定义状态时,我也有很好的机会继续执行该程序。
    • @DaveRook - 我认为最好避免一直捕获普通异常。如果在 try 块中触发了意外的异常,而您只是记录它并继续使用您的应用程序,那么您可能损坏了 AppDomain,或者至少您正在掩盖一个错误。它会产生错误而不是解决它们。
    • 啊,对不起@DaveRook,我是想解决这个问题。创建异常时,您会在异常中获得各种有用的堆栈跟踪信息。再次抛出它会丢失有用的堆栈跟踪。您应该始终抛出一个新异常并将当前异常放置为其InnerException。最好制作类似LoggedException 的东西,这样您就可以获取引发异常的位置的堆栈跟踪。
    • 很抱歉,我只能给那个评论 +1 (而不是更多!)...这是个好主意,谢谢。
    【解决方案3】:

    一般情况下,您需要按类型处理异常(例如catch (SomeSpecificException)

    某些派生异常类型确实有额外的代码,例如

    例如SqlException 有一个 Number 属性,可用于控制流/信息

    catch (System.Data.SqlClient.SqlException sqlEx)
    {
      if (sqlEx.Number == 1205) // Deadlock
         ...
      if (sqlEx.Number == -2) // = TimeOut
         ...
      // etc.
    }
    

    编辑

    实际上,System.Exception确实有一个受保护的HRESULTproperty。请参阅How do I determine the HResult for a System.IO.IOException?How to get Exception Error Code in C#

    虽然不能直接访问,但您可以通过Marshal.GetHRForException(ex) 检索它。不同的异常有不同的HRESULT,例如

    System.Exception :  HRESULT COR_E_EXCEPTION (0x80131500)
    System.SystemException : HRESULT COR_E_SYSTEM (0x80131501)
    

    也就是说,根据其他答案,捕获特定异常仍然是 IMO 的首选机制 - 大概 HRESULT 机制是 COM 后遗症。

    【讨论】:

      【解决方案4】:

      您应该为那些只有您预计代码中可能出现的异常处理并提供有意义的消息,并且可以处理异常。任何您没有预料到的异常,都会显示一条通用消息并将消息记录到日志文件或事件日志中。您可能还想为未处理/意外异常设置策略,以便显示消息以联系支持人员并退出应用程序。

      【讨论】:

        猜你喜欢
        • 2018-06-21
        • 2011-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-07
        • 1970-01-01
        • 2022-10-20
        相关资源
        最近更新 更多