嵌套Try / Catch

时间:2010-02-22 19:54:35

标签: c# nested try-catch

嵌套的Try / Catch是否有一个你没有干净编码的信号?我想知道因为在我的catch中我正在调用另一个方法,如果失败,我会得到另一个运行时错误,所以我很想再次使用另一个try / catch将这些调用包装在catch中。我想知道这样做是否正常?

e.g。

    catch (Exception ex)
    {
        transaction.VoidOrder(transactionID);

        LogError(ex.ToString());
        Response.Redirect("Checkout", false);
    }

因此VoidOrder或甚至LogError方法可能会爆炸。现在,当我调用VoidOrder时,我在transactionID上得到一个空引用,因为它调用了一个BL方法,并且在BL方法中我重新抛出,所以我可以在代码的这个更高级别捕获它以上。但是,如果我再次在捕获物内投掷,那么我也需要抓住它。

5 个答案:

答案 0 :(得分:15)

以下是我们解决问题的方法:

从UI / codebehind级别到其他层的所有调用都使用try-catch,我们总是捕获自定义异常。底层图层采取的所有操作都有自己的try-catch,它会记录,包装并抛出自定义异常。然后,UI可以依赖于此并查找带有友好错误消息的已处理异常。

<强>代码隐藏:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    //do something when a button is clicked...
    try
    {
        MyBL.TakeAction()
    }
    catch(MyApplicationCustomException ex)
    {
        //display something to the user, etc.
        ltlErrorPane.Text = ex.Message;

        //or redirect if desired
        if(ex.ErrorType == MyCustomErrorsType.Transactional)
        {
            Response.Redirect("~/Errors/Transaction.aspx");
        }
    }
}

<强> BL:

在业务层中,任何可能失败的操作都使用try-catch,它会在将问题投放到UI之前记录并解决问题。

public class MyBL
{
    public static void TakeAction()
    {
        try
        {
            //do something
        }
        catch(SpecificDotNetException ex)
        {
            //log, wrap and throw
            MyExceptionManagement.LogException(ex)
            throw new MyApplicationCustomException(ex, "Some friendly error message", MyCustomErrorsType.Transactional);
        }
        finally
        {
            //clean up...
        }
    }
}

异常处理程序:

实际的异常处理程序有多种记录方式,包括事件日志,文件日志,如果其他所有方法都失败,最后发送电子邮件。如果记录器无法执行任何预期的操作,我们选择简单返回false。 IMO这是个人选择。我们认为3种方法连续失败的可能性(事件日志失败,尝试文件记录,失败,尝试电子邮件,失败)是不太可能的。在这种情况下,我们选择允许应用继续。您的另一个选择是允许应用完全失败。

public static class MyExceptionManagement
{
    public static bool LogException(Exception ex)
    {
        try
        {
            //try logging to a log source by priority, 
            //if it fails with all sources, return false as a last resort
            //we choose not to let logging issues interfere with user experience

            //if logging worked
            return true;
        }
        catch(Exception ex)
        {
            //in most cases, using try-catch as a true-false is bad practice
            //but when logging an exception causes an exception itself, we do
            //use this as a well-considered choice.
            return false;
        }
    }
}

最后,作为故障保护,我们实现了Application_Error全局事件处理程序(在Global.asax中)。对于我们没有正确尝试捕捉某些东西的情况,这是最后的手段。我们通常会记录并重定向到友好的错误页面。如果上面的自定义错误处理成功完成,那么很少有错误会进入全局处理程序。

希望这可能会有所帮助。这是一种可能的解决方案。在一些较大的应用程序中,它已经为我们工作了好几年..

答案 1 :(得分:5)

嵌套try/catch块在顶级应用程序中是不可避免的,这些应用程序需要以其他非平凡的方式记录,发送消息或对异常做出反应。

有一些方法可以减少嵌套块的数量(例如,使用ASP.NET的HttpApplication.Error处理程序(又名Application_Error)来整合错误处理),但是您应该捕获由您生成的任何异常处理代码并实施备份计划,以防所有其他方法都失败。

答案 2 :(得分:1)

嵌套问题的另一个解决方案是在这些函数中封装内部函数(LogError等)的try / catch逻辑,而不是依赖于调用者来捕获它们。对于LogError,这是有意义的,因为无论是谁尝试记录错误,您可能都希望以相同的方式处理损坏的错误记录器。

答案 3 :(得分:1)

也许是一个问题是否有人能理解你为什么使用嵌套的try / catch。有时候使用它们是不可避免的,但我说通常不漂亮 你应该考虑将关注点分开是必须的。

getControl方法不应该在其中插入脚本,save方法也不应该执行保存。

检查这些方法究竟应该做什么,然后你会得到答案。如果出现错误,将订单归零看起来并不那么尴尬。听起来很合理。

答案 4 :(得分:0)

您是否考虑过使用TransactionScope对象而不是尝试手动回滚事务?我知道有时候这是不可能的,但对我来说,大多数情况下,TransactionScope都是一种享受。这样,我不必手动管理回滚项目 - 无论如何,手动回滚可能是一个问题,因为数据处于“不稳定”状态,这可能会弄乱你的整个逻辑。