在.NET中输入finally块之前是否可以检测是否发生了异常?

ygo*_*goe 2 .net c# exception

Java也提出了同样的问题,但我对.NET的答案很感兴趣.

请考虑以下代码:

class Program
{
    static void Main()
    {
        try
        {
            RunTransaction();
            // If there was an exception within the transaction,
            // I won't be here anymore. But if the transaction was
            // cancelled without an exception being thrown, I really
            // need to know because I must stop here anyway.
            OtherCode();
        }
        catch (Excexption ex)
        {
            // Log the exception...
            // If an exception was thrown in the transaction scope,
            // this must be logged here. If a "helper" exception was
            // created in the Dispose method, this may be logged, but
            // it won't say much. It just made sure that nothing else
            // was executed in this try block.
        }
    }

    static void RunTransaction()
    {
        using (var trans = new Transaction())
        {
            // An error may occur here and it should be logged.
            throw new Exception();
            // Maybe the scope is simply left without an exception.
            return;
            // Otherwise, the transaction is committed.
            trans.Commit();
        }
    }
}

class Transaction : IDisposable
{
    bool isCommitted;

    public void Commit()
    {
        isCommitted = true;
    }

    public void Dispose()
    {
        if (!isCommitted)
        {
            // Was an exception thrown before this is called?
            // If not, I might consider throwing one here.
            // I can't always throw an exception here because if
            // another exception is already propagated, it would
            // be dropped and the real error cause would not be
            // visible anymore.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在该Transaction.Dispose方法中,我如何知道是否已抛出异常?

请注意,finally此处未显式显示该块,但隐藏在using调用该IDisposable.Dispose方法的语句中,此处显示该方法.

更新:我的背景是我有一个行为包装类,行为有点像TransactionScope.但是TransactionScope太多魔术并没有按预期工作,所以我回到真正的数据库交易.有些方法需要一个事务,但是如果它们是从另一个已经需要事务的方法调用的,那么内部"事务"必须"连接"外部事务而不是从数据库请求一个新的嵌套事务,这在任何地方都不受支持.了解.真实代码比我的样本复杂一点,内部事务可能被取消,有效地结束了事务.然后,如果在外部事务中继续运行任何东西,它不再存在,则无法回滚,但会在任何事务之外有效地运行!必须一定要防止这种情况.首先处理异常就可以了,但是内部事务也可以在没有它的情况下取消.这是我想在我的作用域助手类中检测到的.

dca*_*tro 6

public void Dispose()
{
    if (!isCommitted)
    {
        // Was an exception thrown before this is called?
        // If not, I might consider throwing one here.
        // I can't always throw an exception here because if
        // another exception is already propagated, it would
        // be dropped and the real error cause would not be
        // visible anymore.
    }
}
Run Code Online (Sandbox Code Playgroud)

你说你想抛出异常,Dispose如果没有抛出异常.

Dispose不应该抛出异常.从实现Dispose方法:

为了确保始终适当地清理资源,Dispose方法应该可以多次调用,而不会抛出异常.

同样来自Dispose Pattern:

避免从内部抛出异常,Dispose(bool)除非在包含进程已被破坏的临界情况下(泄漏,不一致的共享状态等).

用户希望调用Dispose不会引发异常.

如果Dispose可能引发异常,则最终块清理逻辑将不会执行.要解决这个问题,用户需要Dispose在try块中包含每个调用(在finally块中!),这会导致非常复杂的清理处理程序.如果执行Dispose(bool disposing)方法,则在disposing为false时永远不会抛出异常.如果在终结器上下文中执行,这样做将终止进程.

  • @JohnnyMopp是的,他想知道*因为*他想要从'Dispose`中抛出异常,如果还没有抛出的话.但是因为`Dispose`不应该抛出异常,所以这一点没有实际意义. (2认同)