【问题标题】:Does wrapping and rethrowing an exception impact performance?包装和重新抛出异常会影响性能吗?
【发布时间】:2013-01-15 17:43:09
【问题描述】:

我在我的应用程序中遵循了这种处理异常的方式。但是我的领导说我做错了。我只是包装并重新抛出相同的异常,这会影响性能。

我的方法有什么问题?有人对我如何在这里记录和处理异常有任何建议吗?

public class BusinessRepository : IBusinessRepo
{
    public List<Employee> GetEmployees()
    {
        try
        {
            //do some DB operations
        }
        catch (SQLException sqlex)
        {
            Logger.Log("Exception detail with full stack trace");
            throw new DALException(sqlex, "Error in data access layer");
        }

    }
}
public class BusinessLayerClass : IBusinessLayer
{
    private readonly IBusinessRepo Repo;
    public BusinessLayerClass(IBusinessRepo rep)
    {
        Repo = rep;
    }
    public List<Employee> GetEmployees()
    {
        try
        {
           List<Employee> emps= return Repo.GetEmployees();
        }
        catch (DALException dex)
        {
            //do nothin as it got already logged
            throw;
        }
        catch (Exception ex)
        {
            Logger.Log(ex, "Business layer ex");
            throw new BusinessLayerEx(ex);
        }
    }
}

public class HomeController : Controller
{
    public ActionResult Index()
    {
        try
        {
            List < Employee >= BusinessLayerClass.GetEmployees();

        }
        catch (DALException)
        {
            //show error msg to user
        }
        catch (BusinessLayerEx)
        {
            //show error msg to user
        }
        catch (Exception ex)
        {
            Logger.Log();
            //show error msg to user
        }
        return View(emps);
    }
 }

我是否遵循上述正确的冒泡、处理和记录方式?

【问题讨论】:

  • 根据 john skeet 的说法,异常抛出几乎不会影响性能。见:developerfusion.com/article/5250/…
  • 既然异常应该是异常的,那么重要吗?
  • @albertjan 我同意 Jon Skeet。但是我的方法是正确的处理和记录方式吗?
  • 我发现真正令人震惊的是“它已经被记录”的断言,我不是指语法。这只能意味着在 Repo 中有 另一个 try-catch 引诱。

标签: c# asp.net-mvc asp.net-mvc-3 exception-handling


【解决方案1】:

我倾向于同意你这样做的方式,只要满足两个条件:

  1. 您的Logger.Log 语句记录的内容比您在此处指出的内容更有意义/有用(我猜您的代码在这里只是一条指示错误已记录的示例消息)。如果它提供了可用于追踪异常原因的信息,那就太好了。
  2. 您的//show error msg to user cmets 表示,在该位置,您渲染了一个很好的视图,说明发生了错误,并且您不只是显示默认的异常屏幕/轨迹跟踪。

就你的throw; 而言,当你捕捉到你刚刚抛出的 DALException 时:没关系。您在这里的目标似乎是捕获来自前一层的任何异常并记录它,然后抛出您自己的异常。由于只有在您已经记录了另一个错误并自己抛出它时才会抛出 DALException,所以让它冒泡超过这个级别是完全可以的。

【讨论】:

    【解决方案2】:

    异常的一般经验法则是不要捕获它们,除非你可以“做点什么”,即增加价值。理想情况下,这将是某种优雅的恢复,直到用户永远不知道发生了故障,但至少这将包括记录异常——你正在做的事情。

    不要为了立即重新抛出异常而捕获异常。那没有任何价值。 (如果您需要将异常类型更改为更具信息性/更适合上下文的内容,则可能是一个例外)。

    【讨论】:

    • 他捕捉到异常做某事(改变它或记录信息)然后然后重新抛出它,他没有捕捉到它什么都不做,而是重新抛出相同的异常,所以这不适用。
    • catch-then-rethrow 代码只是为了从后面的“catch, log, throw new exception”块中过滤掉一种特定类型的异常(因为这种类型的异常只会得到如果问题已被记录,则抛出那里)。
    • @Servy 不,他抓住了它,除了再次扔它之外什么也没做。他甚至在那里发表了评论,说明他故意什么都不做以及为什么 - “它已经被记录了”。
    • 然而,放置一些集中的异常 logging 几乎总是一个好主意。我希望人们绝对不要将“句柄”一词用于捕获异常的任何事物,因为它确实应该比这更多。 ;)
    • @TheDag 他抓住它并重新投掷,这样他就可以防止它被记录两次。您是否有任何替代方案会导致相同的行为?
    【解决方案3】:

    与任何正常的返回机制相比,抛出和捕获异常的代价是昂贵的,但这有点无关紧要——我们不应该将异常用作正常的控制流机制,而是要处理异常的事情。

    异常处理在技术上可能非常具有挑战性。毕竟,大多数时候我们完全没想到它们。但是,当团队或项目根本没有任何类型的错误处理策略时,几乎不可能“正确”处理异常。在一个理想的世界里,我们会在一开始就确切地知道我们需要处理什么样的错误条件,并且我们会在设计整个应用程序时考虑到这些情况(以及我们还需要记住的大量其他约束,从代码可读性到性能)。

    我会说,如果您的领导说“这是错误的”,那么问“我们的错误处理策略是什么?”是公平的。如果您甚至不知道您的代码应该实现什么目的,您怎么可能交付出色的代码?

    【讨论】:

      【解决方案4】:

      您的方法没有任何问题,但我认为您的自定义异常不会增加太多价值。在 DAL 中包装异常可以增加价值的一个示例是,如果您将特定的 SQL 异常(例如唯一键违规)包装在自定义异常中,以便您的 UI 可以显示有意义的错误消息。

      至于性能,反正这并不重要,因为已经发生了非常糟糕的事情。

      【讨论】:

      • 我总是听到同样的声音,它有非常糟糕的影响,但由于你所说的,也许它的影响只是在调试时......除了那些在投掷前进行大量检查的人之外,还有超时,这可能会让人们相信。仍然,认为第一个人是对的,我有一个异常来了,我想将它们更改为特定类型的异常,在与整个应用程序异常混合之前,是否可以捕获、重新创建新实例并重新抛出它?有没有提高性能的投掷方法?
      • 您可以阅读 Jon Skeet 的第一条评论中的链接,以更好地了解异常和性能 (developerfusion.com/article/5250/…)。我的观点是,对于大多数应用程序,您应该以对应用程序有意义的方式处理异常,而不必担心性能。
      猜你喜欢
      • 1970-01-01
      • 2010-12-18
      • 1970-01-01
      • 2020-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-24
      • 2018-03-25
      相关资源
      最近更新 更多