采用以下最小例子:
try { foo }
finally { bar() }
foo
可能会或可能不会投掷,而bar()
可能会或可能不投掷。
如果两个函数都抛出,则bar()
抛出的异常将覆盖foo
抛出的异常。但是,我需要查看foo
引发的异常。我能控制的唯一代码是bar()
内部。
在C ++中,可以通过选中std::uncaught_exceptions
内的bar()
来实现。
C#怎么样?
有a check using Marshal.GetExceptionPointers(),但正如答案所述,这是一个可怕的黑客攻击,在我的情况下它是不够的,因为我的代码需要在Mono上运行,而Mono没有实现该功能。
上下文:
在我的实际案例中,foo
是一个由库用户提供的大块代码,可能会抛出各种异常,而bar()
是Dispose
函数这是由我提供并自动调用的。
答案 0 :(得分:0)
您需要手动编码:
// Whether an exception has been thrown from the main block.
bool hasMainException = false;
try
{
foo();
}
catch
{
// Record that exception has been thrown from main block, and rethrow.
hasMainException = true;
throw;
}
finally
{
// Execute secondary block within its own try-catch block.
try
{
bar();
}
catch
{
// Only rethrow exception from secondary block if there isn't
// already an exception from the main block.
if (!hasMainException)
throw;
}
}
顺便说一句,我需要实现一些非常类似于涉及Dispose
方法的用例,因此我写了一些扩展方法来实现这一点,以及支持所有用例的各种策略。请参阅DisposableExtensions
和DisposeExceptionStrategy
。您感兴趣的策略是Subjugate
。
答案 1 :(得分:0)
这将
foo
引发异常,即使bar
中引发了异常。bar
没有例外,则foo
引发例外。保留原始堆栈跟踪中的任何一个异常。
ExceptionDispatchInfo exceptionInfo = null;
try
{
foo();
}
catch(Exception ex)
{
exceptionInfo = ExceptionDispatchInfo.Capture(ex);
}
finally
{
try
{
bar();
}
catch(Exception ex)
{
exceptionInfo = exceptionInfo ?? ExceptionDispatchInfo.Capture(ex);
}
}
exceptionInfo?.Throw();