【问题标题】:C# Error handling catch blocksC# 错误处理 catch 块
【发布时间】:2013-01-21 12:40:57
【问题描述】:

为什么大多数时候建议我们不应该捕获像“异常”这样的错误,而是捕获我们作为开发人员所期望的错误。 捕获通用错误是否会影响性能,还是从最佳实践的角度推荐?

  try
  {
        // Do something
  }
  catch(Exception e)
  {
        //Log error
  }

【问题讨论】:

  • 你真的准备好处理OutOfMemoryException吗?
  • 这是一个非常笼统的问题,可以有很多自以为是和有争议的答案。在我个人的意见答案中,只捕获您想要处理的预期异常。例如,打开文件并捕获文件访问异常以允许自己在放弃之前重试几次,或者文件不存在异常,因为您可能希望专门向客户端发送有关此的消息。意外的异常应该冒泡并由您的记录器记录并生成对客户端友好的oops 页面。然后根据需要从那里进行更改。

标签: c#


【解决方案1】:

最佳做法是先捕获特定异常,然后再处理更通用的异常。

Exception Handling (C# Programming Guide)

可以链接多个具有不同异常过滤器的 catch 块 一起。捕获块在您的 代码,但每个异常只执行一个 catch 块 抛出。第一个指定确切类型或基数的 catch 块 抛出异常的类被执行。如果没有指定 catch 块 一个匹配的异常过滤器,一个没有过滤器的 catch 块 被选中,如果语句中存在一个。 重要的是 定位具有最具体(即最 派生的)异常类型优先。

对于您的问题:

为什么大部分时间都建议我们不要捕获错误,例如 “异常”,但会捕获我们作为开发人员所期望的错误。

一个例子是捕捉NullReferenceException。捕获 NullReferenceException 从来都不是一种更好的做法,相反,在使用其实例成员之前,应该始终检查对象是否为空。例如在字符串的情况下。

string str = null;
try
{
   Console.WriteLine(str.Length)
}
catch(NullReferenceException ne)
{
    //exception handling. 
}

相反,应该进行检查以检查空值。

if(str != null)
   Console.WriteLine(str.Length);

编辑:

我想我的问题是错误的,如果你问的是哪个异常应该被捕获,哪些不应该那么 IMO,那些可以处理的异常应该被捕获并且休息应该留在库中,这样它们就可以冒泡直到上层进行适当的处​​理。一个例子是违反主键约束。如果应用程序正在从用户那里获取输入(包括主键)并且该日期被插入到数据库中,则可以捕获该异常并向用户显示一条消息“记录已存在”,然后让用户输入一些不同的价值。

但是如果异常与外键约束有关(例如,下拉列表中的某些值被认为是无效的外键),那么该异常应该冒泡,并且通用异常处理程序应该将其记录在适当的位置。

例如在 ASP.Net 应用程序中,这些异常可以记录在 Application_Error 事件中,并且可以向用户显示一般错误页面。

编辑 2: 对于OP的评论:

如果处于低水平,是否会出现性能下降 尽管知道错误是否存在,但仍捕获一般错误 sql异常

即使会有任何性能差异,也应该可以忽略不计。但是捕获特定异常,如果您知道异常将是SqlException,那么捕获它。

【讨论】:

  • 我认为问题不在于如何订购 catch 块。
  • @Jon,可能是,但我的回复是针对这句话Why is it adviced most of the time that we should not trap errors like "Exception" but trap errors that we expect as developers. --
  • 这个答案的当前形式根本没有回答你提到的问题。 OP 询问“为什么我应该/不应该写 catch(Exception) 而不是例如 catch(ObjectDisposedException)”,而不是“如果有多个块,我如何订购 catch 块”。
  • @Jon:目前的问题形式使得它非常无法回答,因为它是一般性的,在我的谦卑意见中没有建设性。关于这个话题有很多个人偏好和反对意见,所有这些都可能是对的,也可能是错的,并且以一种或另一种方式非常有争议,我认为一般不适合问答。
  • @Jon ,我真的想了解在低级别是否会在捕获通用错误时出现性能下降,尽管知道错误是否是 sqlexception
【解决方案2】:

您应该只捕获您可以处理的异常。 Exception 太笼统了,所以大多数时候你不能说你能应付。这有点好笑,但你应该只捕获除你之外的异常:)

有些情况你需要捕捉Exception,但很少见,你应该在大多数情况下避免它。通常它表示一些设计问题。

【讨论】:

  • peter 这是有道理的,我真正想知道的问题是,如果有人只处理异常,那么会不会出现性能问题而不是捕获特定异常,例如 SQLEXCEPTION?跨度>
  • 我认为异常类型不会产生任何性能差异。顺便说一句,如果您遇到异常处理的性能问题,那么问题就出在其他地方。这里有几篇关于这个主题的文章:stackoverflow.com/a/891230/238682我推荐所有这些。
【解决方案3】:

检查Eric Lippert's blog(令人烦恼的异常)了解处理异常的最佳方式。

• 不要捕获致命异常;无论如何,您对它们无能为力,并且试图使情况变得更糟。

• 修复您的代码,使其永远不会触发愚蠢的异常——生产代码中绝不应该发生“索引超出范围”异常。

• 尽可能通过调用那些在非异常情况下抛出的烦人方法的“尝试”版本来避免烦人的异常。如果您无法避免调用令人烦恼的方法,请捕获其令人烦恼的异常

• 始终处理表示意外外部条件的异常;一般来说,预测每一个可能的失败是不值得或不切实际的。只需尝试操作并准备处理异常。

【讨论】:

    【解决方案4】:

    比要求更频繁地使用异常处理实际上是一种懒惰的编程方式。假设您有一个DataTable,并且您想访问第一行。

    public DataRow AccessFirstRow(DataTable dt)
    {
      try
      {
        return dt.Rows[0];
      }
      catch (Exception e)
      {
        //There isn't a first row or dt is null
      }
    }
    

    代替

    public DataRow AccessFirstRow(DataTable dt)
    {
      if(dt != null)
       if(dt.Rows.Count > 0)
         return dt.Rows[0];
      //If we can't access dt, then don't
      return null;
    }
    

    我的经验法则是:

    只能在例外情况下使用例外。

    如果您确实决定处理它们,如上所述处理您知道可能会遇到的特定异常,而不是一般异常。

    【讨论】:

      【解决方案5】:

      这是一个最佳实践。这个想法是,您应该快速明确地处理已知异常,同时在程序中设置更普遍的异常,因为意外异常可能是由一些更主要/基本错误引起的。

      【讨论】:

        【解决方案6】:

        捕捉那些你打算处理的异常。您通常希望在这样的上下文(方法)中处理特定的异常,在这种情况下,您有足够的信息来处理报告的错误(例如,访问用于清理的对象)。

        如果 try 块中的代码抛出不同类型的异常,您可能希望在同一方法中处理一些异常并重新抛出其他异常,以便在调用方方法中处理它们(因为在该上下文中,您有资源处理这些异常)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-10
          • 1970-01-01
          • 2019-05-19
          • 1970-01-01
          相关资源
          最近更新 更多