Leo*_*Hat 1 c# resources exception
我正在使用一些代码,它们使用异常来处理某些错误条件(当然不是最好的设计,但它正是我正在使用的).
当代码中发生异常时,我需要一种优雅的方法来清理任何开放或临时资源.
这可以这样执行:
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
}
}
Run Code Online (Sandbox Code Playgroud)
假设该foo()方法在自身之后正确清理,但该bar()方法引发了异常.在清理代码中,我们将cleanupResourceFoo() 首先调用它本身将抛出异常,因为foo资源已经被清理.
这意味着cleanupResourceBar()最终不会被调用,我们最终会导致资源泄漏.
当然我们可以try/catch像这样重写内部块:
try
{
cleanupResourceFoo();
}
catch
{
}
try
{
cleanupResourceBar();
}
catch
{
}
Run Code Online (Sandbox Code Playgroud)
但现在我们变得非常难看.
我来自C++背景,这是我通常使用RAII的东西.有关在C#中处理此问题的优雅方法的任何建议?
清理资源应该几乎总是通过using语句来处理IDisposable- 所以你只需要:
using (FirstResource r1 = ...)
{
using (SecondResource r2 = ...)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
如果你只是想清理资源上的异常,这是比较少见-而不是我所期待RAII以特别帮助您在C++中.您可以使用委托来使这更简单:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
通过不捕获异常,这允许错误传播而不是被吞噬.这通常是你想要的 - 如果不是你的情况,或许你可以更准确地解释你的情况.
你已经说过,你有效地想要忽略非致命的异常 - 但是你通常不应该只抓住Exception并继续前进:捕捉你在特定情况下所期望的特定异常.显然你可能有一个非常特殊的情况,但这是大多数时候都持有的一般建议.如果你真的想要,你可以重构上面的帮助方法以捕获异常.