拦截IDisposable.Dispose中的异常

Jam*_*ing 29 .net c# idisposable

在该IDisposable.Dispose方法中有一种方法可以确定是否抛出异常?

using (MyWrapper wrapper = new MyWrapper())
{
    throw new Exception("Bad error.");
}
Run Code Online (Sandbox Code Playgroud)

如果在using语句中抛出异常,我想在处理IDisposable对象时知道它.

Kel*_*lyn 18

您可以IDisposable使用方法扩展Complete并使用以下模式:

using (MyWrapper wrapper = new MyWrapper())
{
    throw new Exception("Bad error.");
    wrapper.Complete();
}
Run Code Online (Sandbox Code Playgroud)

如果在using语句中抛出异常,则Complete之前不会调用该语句Dispose.

如果您想知道抛出了什么确切的异常,那么订阅AppDomain.CurrentDomain.FirstChanceException事件并将最后抛出的异常存储在ThreadLocal<Exception>变量中.

这种模式在TransactionScope课堂上实施.


Sam*_*ron 16

,在.Net框架中没有办法做到这一点,你无法弄清楚finally子句中正在抛出的当前异常.

在我的博客上看到这篇文章,为了与Ruby中的类似模式进行比较,它突出了我认为存在于IDisposable模式中的差距.

Ayende有一个技巧,可以让你检测到发生的异常,但是,它不会告诉你它是哪个异常.


Jo *_*VdB 5

这是不可能捕获的异常Dispose()的方法.

但是,可以检查Marshal.GetExceptionCode()Dispose以检测是否确实发生了异常,但我不会依赖它.

如果您不需要类并且只想捕获Exception,则可以创建一个接受在try/catch块中执行的lambda的函数,如下所示:

HandleException(() => {
    throw new Exception("Bad error.");
});

public static void HandleException(Action code)
{
    try
    {
        if (code != null)
            code.Invoke();
    }
    catch
    {
        Console.WriteLine("Error handling");
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

例如,您可以使用自动执行事务的Commit()或Rollback()并执行某些日志记录的方法.通过这种方式,您并不总是需要try/catch块.

public static int? GetFerrariId()
{
    using (var connection = new SqlConnection("..."))
    {
        connection.Open();
        using (var transaction = connection.BeginTransaction())
        {
            return HandleTranaction(transaction, () =>
            {
                using (var command = connection.CreateCommand())
                {
                    command.Transaction = transaction;
                    command.CommandText = "SELECT CarID FROM Cars WHERE Brand = 'Ferrari'";
                    return (int?)command.ExecuteScalar();
                }
            });
        }
    }
}

public static T HandleTranaction<T>(IDbTransaction transaction, Func<T> code)
{
    try
    {
        var result = code != null ? code.Invoke() : default(T);
        transaction.Commit();
        return result;
    }
    catch
    {
        transaction.Rollback();
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我希望 `Dispose` 已被定义为采用类型为 `Exception` 的参数,该参数将指示在 try/finally 上下文(如果有)*保护对象* 中有什么异常(如果有)未决。查询线程是否有异常挂起并不是一回事,因为 `Dispose` 本身可能会在 try/finally 块中调用,该块嵌套在保护要处理的对象的块中。 (2认同)