c# - 可能抛出异常时清理多个资源的优雅方式

标签 c# exception resources

我正在编写一些大量使用异常来处理某些错误情况的代码(当然这不是最好的设计,但我正在使用它)。

当代码中发生异常时,我需要一种优雅的方式来清理所有打开的或临时的资源。

这可以像这样执行:

try
{
    foo();
    bar();
}
catch (Exception)
{
    // Oops, an error occurred - let's clean up resources
    // Any attempt to cleanup non-existent resources will throw
    // an exception, so let's wrap this in another try block
    try
    {
        cleanupResourceFoo();
        cleanupResourceBar();
    }
    catch
    {
        // A resource didn't exist - this is non-fatal so let's drop
        // this exception
    }
}

假设 foo() 方法自行正确清理,但 bar() 方法抛出异常。在清理代码中,我们将调用 cleanupResourceFoo()首先,因为 foo 资源已经被清理,它本身会抛出异常。

这意味着 cleanupResourceBar() 不会被调用,我们将以资源泄漏告终。

当然我们可以像这样重写内部的 try/catch block :

try
{
    cleanupResourceFoo();
}
catch
{
}
try
{
    cleanupResourceBar();
}
catch
{
}

但现在我们变得很丑陋。

我有 C++ 背景,这是我通常会使用 RAII 的那种东西。关于在 C# 中处理此问题的优雅方式的任何建议?

最佳答案

清理资源应该几乎总是通过 using 语句和 IDisposable 来处理 - 所以你只需:

using (FirstResource r1 = ...)
{
    using (SecondResource r2 = ...)
    {
        ...
    }
}

如果您想在出现异常时清理资源,这种情况比较少见——而且我不希望 RAII 在 C++ 中特别帮助您。您可以使用委托(delegate)来简化此操作:

TryWithCleanUpOnException(foo, cleanUpResourceFoo);
TryWithCleanUpOnException(bar, cleanUpResourceBar);

...

private static void TryWithCleanUpOnException(Action action,
                                              Action cleanUp)
{
    bool success = false;
    try
    {
        action();
        success = true;
    }
    finally
    {
        if (!success)
        {
            cleanup();
        }
    }
}

通过不捕获异常,这允许错误传播而不是被吞噬。这通常是您想要的 - 如果不是您的情况,也许您可​​以更准确地解释您的情况。

您已经说过,您实际上想要忽略一些非致命异常 - 但您通常不应该只捕获 Exception 并继续:捕获特定您在特定情况下期望的异常。显然,您的情况可能非常特殊,但这是在大多数情况下都适用的一般性建议。如果确实需要,您可以重构上面的辅助方法以捕获异常。

关于c# - 可能抛出异常时清理多个资源的优雅方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7412153/

相关文章:

c# - TimeSpan 到自定义字符串,如 HH :mm:ss

c# - 在 WPF 中打开 WebView2 会在调用 EnsureCoreWebView2Async 时导致 System.UnauthorizedAccessException

java - 发生错误::java.lang.OutOfMemoryError:Java 堆空间

java - getResource 和 getResourceAsStream 返回 null

c# - react 性扩展 (RX) 自定义调度程序 C#

c# - .NET 4.5 Async/Await 和垃圾收集器

java - 无法从任何地方构建 Hibernate SessionFactory 异常

java - Bean创建异常: Injection of autowired dependencies failed

resources - Airflow :如何指定资源池的定量使用?

graphics - 是否有任何来源可以获取可负担得起的软件产品和游戏图形和声音?