【问题标题】:Handling exception in Dispose()在 Dispose() 中处理异常
【发布时间】:2016-09-21 10:29:21
【问题描述】:

我有一个 UnitOfWork 类,它根据块中的错误提交或回滚事务。

class UnitOfWork: IDispose
{
        public void Dispose()
        {
                if (Marshal.GetExceptionCode() == 0 
                   || Marshal.GetExceptionPointers() == IntPtr.Zero)
                {
                       // Commit
                }
                else
                {
                      // Rollback
                }
            }
        } 
}

这个类的使用方式如下:

try
{
    using (var uow = new UnitOfWork())
    {
        // Do something here that causes an exception
    }
}
catch
{
    using (var uow = new UnitOfWork())
    {
        // Log exception
    }
}

我浏览了这篇文章: Detecting a Dispose() from an exception inside using block

在上述问题中,Steven(其中一位回答者)提到,如果我在 Dispose() 中检测到“try”部分的“using”块的异常,我无法在“catch”块并将错误记录到数据库(因为 Dispose() 中的“Marshal”代码将继续说存在异常),这意味着 ExceptionCode 和 ExceptionPointers 将从 try 块“浮动”(?)到 catch块。

但是,就我而言,这可以正常工作 - 即。如果在“try”部分的“using (var uow = new UOW)”块中有异常,它会正确捕获异常,然后在 catch 块中,“if”条件通过,导致提交发生并允许我来记录异常。

归结为我对 Marshal.GetExceptionPointers() 的工作原理不完全了解。有人可以确认我的使用模式是否可以正常工作(到目前为止,所有测试似乎都表明它可以正常工作)以及 Marshal.GetExceptionPointers() 到底在做什么?

【问题讨论】:

    标签: c# error-handling marshalling dispose


    【解决方案1】:

    IDisposable.Dispose 旨在释放资源,将提交/回滚操作放入其中是一个坏主意。调用者应该知道如何处理异常以及如何回滚。

    using (var unitOfWork = new UnitOfWork())
    {
        try
        {
            Prepare();
            Step1();
            Step2();
            unitOfWork.Commit();
        }
        catch(PrepareException e)
        {
            //no necessary to rollback, just log it
        }
        catch(FirstStepException e1)
        {
            //rollback step1
        }
        catch(SecondStepException e2)
        {
            //rollback step1 and step2
        }
    }
    

    【讨论】:

    • 虽然将 Commit 放入 Dispose 肯定是个坏主意,但将 Rollback 放在那里却没有,而且实际上在很多地方都做了,包括标准的 DbTransaction、TransactionScope 等。
    • @Evk 问题是有时没有全局回滚解决方案。只有调用者知道做了什么以及需要回滚什么。查看我的编辑。
    • 但是您还有什么其他选择(如果我们谈论抽象事务和它的 Dispose 方法)?您不能在 Transaction.Dispose 中应用部分更改。无论如何,您都必须提交或回滚。
    • 我不知道为什么这是个坏主意? Dispose 正在释放资源,但 UnitOfWork 类引用了一个 SqlDAO 类(它封装了一个 SqlConnection 类)。在触发 sqlDao 上的 dispose 之前,我显式回滚或提交事务。你预见到什么问题?
    猜你喜欢
    • 2021-01-01
    • 2012-04-28
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 1970-01-01
    • 2020-06-26
    相关资源
    最近更新 更多