C# - 异常投掷的无限循环?

时间:2014-07-25 17:23:04

标签: c# .net sqlite exception exception-handling

我有以下代码:

protected void ExecuteInTransaction(Action action)
{
    using (SQLiteTransaction transaction = connection.BeginTransaction())
    {
        try
        {
            action.Invoke();
            transaction.Commit();
        }
        catch(Exception)
        {
            transaction.Rollback();
            throw;
        }
    }
}

在测试此类时,我设法抛出异常以测试catch 分支

Exception Thrown

当我在调试模式下,我继续执行此抛出,以查看调用类如何处理它,但异常是永远不会被方法抛出,相反,它就像不断被抛出并被捕获,抛出并重新捕获,永远不会退出函数

发布模式下,应用程序冻结并停止工作:

Frozen Application

有谁知道为什么会这样,我怎么能避免呢?

提前致谢!

4 个答案:

答案 0 :(得分:3)

没有无限循环。 Visual Studio只停留在未捕获的异常将中止程序的位置。 尝试继续没有任何作用,因为没有进一步执行(VS只是再次显示相同的消息以提醒您)。

如果你在某个调用函数中有一个try / catch处理程序,你就可以调试到那里。 (但是如果那个捕获处理程序再次重新抛出,VS也会停在那里。)


请注意SQLiteTransaction会在处理未结交易时自动处理回滚;它的设计使您的代码更简单:

protected void ExecuteInTransaction(Action action)
{
    using (var transaction = connection.BeginTransaction())
    {
        action.Invoke();
        transaction.Commit();
    }
}

答案 1 :(得分:1)

你确定在堆栈中catch可以处理这个错误吗?您显示的对话框是您在程序的Main方法顶部未处理异常时看到的内容。调试器消息实际上告诉您它未被处理,因此没有下一个语句可以步骤。

答案 2 :(得分:0)

  

有谁知道为什么会这样,我怎么能避免呢?

很难说没有看到你的电话堆栈。

一般来说,有3种可能的选择:

  1. 异常被捕获到了堆栈中。

  2. 你的调用堆栈中某处有一个内核模式系统调用,并且异常被吞下。这仅在64位窗口上运行32位应用程序时发生。最值得注意的示例是OnLoad()的{​​{1}}方法中抛出的异常。有关详细信息,请参阅VS2010 does not show unhandled exception message in a WinForms Application on a 64-bit version of Windows

  3. Form线程上抛出异常,而不是传播回主线程​​。

答案 3 :(得分:-1)

从catch块中取出throw;代码。如果您想知道代码何时进入catch块,请使用断点或Debug.WriteLine()

try / catch的catch块不会捕获自身抛出的异常。所以throw;代码正在创建一个未处理的异常。如果要测试catch块中的代码,请将throw;代码添加到try块的末尾。

修改 我没有意识到OP希望例外传播链。他没有提到在链上传播的异常,他的代码显示不支持传播的异常,因为他没有显示调用此ExecuteInTransaction(Action)方法的代码。 catch块可以重新抛出它捕获的异常。我同意这一点。但是代码catch(Exception){ throw; }不会重新进入相​​同的catch块。如果它会创建一个无限循环,那不会发生什么。如果有一个try / catch块,那么外部catch块将捕获重新抛出的异常,但是他的代码只包含一个catch块。因此,当它试图重新抛出异常时,没有什么可以捕获它并且应用程序中断了。

尝试这样的事情:

private void Main()
{
    // Instantiate action variable. I know this wouldn't work, but it's just for show.
    Action myAction;
    try
    {
        ExecuteInTransaction(myAction);
    }
    catch(Exception ex)
    {
        Debug.WriteLine("Error happened and transaction rolled back. " + ex.Message);
    }
}

protected void ExecuteInTransaction(Action action)
{
    using (SQLiteTransaction transaction = connection.BeginTransaction())
    {
        try
        {
            action.Invoke();
            transaction.Commit();
        }
        catch(Exception ex)
        {
            transaction.Rollback();
            throw ex;
        }
    }
}