如何检测何时从catch块中调用当前正在执行的代码?
void SomeFunction()
{
// how do I detect whether I am being called from within a catch block?
}
编辑:
对于那些提问,我想要实现这样的类,不要错过错误冒泡逻辑:在编写此代码示例时,我收到编译器错误"没有参数的throw语句不是允许在捕获条款之外#34;无论如何,这有点摧毁了我的想法。
public class ErrorManager {
public void OnException(Exception ex) {
LogException(ex);
if (IsInsideCatchBlockAlready()) {
// don't destroy the stack trace,
// but do make sure the error gets bubbled up
// through the hierarchy of components
throw;
} else {
// throw the error to make it bubble up
// through the hierarchy of components
throw ex;
}
}
void LogException(Exception ex) {
// Log the exception
}
bool IsInsideCatchBlockAlready() {
// How do I implement this?
}
}
答案 0 :(得分:3)
你不是。没有办法知道,如果你抛出异常,它会被抓住或崩溃程序。您可以使用代码分析工具在编译时潜在进行猜测,但在代码运行时,这不是一个选项。
答案 1 :(得分:2)
不,没有办法做到这一点。
通过分析生成的(IL)代码可能会有一些偷偷摸摸的方式,但我很确定你不希望这样。
这是来自标准控制台应用程序的IL捕获异常:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 34 (0x22)
.maxstack 1
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: ldstr "OK"
IL_0007: call void [mscorlib]System.Console::WriteLine(string)
IL_000c: nop
IL_000d: nop
IL_000e: leave.s IL_0020
} // end .try
catch [mscorlib]System.Exception
{
IL_0010: pop
IL_0011: nop
IL_0012: ldstr "Err"
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: nop
IL_001e: leave.s IL_0020
} // end handler
IL_0020: nop
IL_0021: ret
} // end of method Program::Main
如果您可以分析当前代码(例如它位于"OK"
)是否在该块内,则可以提取try ... catch
块。这当然不需要考虑其他方法。
这对你所遇到的问题来说也是一个荒谬的解决方案,所以在你把自己扔进一些你不想要的东西之前,先考虑一下你是否真的想要这样做。
答案 2 :(得分:1)
你问了一个错误的问题,我的朋友!
大多数框架允许特定方法处理未捕获的异常。 WPF,C#webforms,asp,所有这些都有一个"未处理的异常处理"例程,你可以在应用程序级别挂钩。
例如,正常的C#表单应用程序使用:
Application.ThreadException += new ThreadExceptionEventHandler(MyCommonExceptionHandlingMethod)
private static void MyCommonExceptionHandlingMethod(object sender, ThreadExceptionEventArgs t)
{
//Exception handling...
}
因此,您只需要声明您的exceptionmanager类,然后将该类挂钩到异常处理中,例如:
Application.ThreadException += new ThreadExceptionEventHandler(TellMyClass)
private static void TellMyClass(object sender, ThreadExceptionEventArgs t)
{
ExceptionManager.HandleException(sender, t);
}
但是,我使用的模式是:
public static class UnhandledExceptionManager {
Logger _logger;
public static void RegisterToHandleFormsException(){
_logger = new Logger();
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += OnThreadException;
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
}
public static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e){
HandleException((Exception)e.ExceptionObject);
}
private static void HandleException(Exception exception, [CallerMemberName] string methodName = "")
{
try
{
_logger.Error(methodName, exception);
}
catch (Exception e)
{
Debug.WriteLine("({0}) {1}", methodName, e);
}
}
}
Program.cs中使用了哪些:
public static void Main(){
UnhandledExceptionManager.RegisterToHandleFormsException();
//etc
}
答案 3 :(得分:1)
Windows上的CLR例外 只是另一个SEH。阅读经典:A Crash Course on the Depths of Win32™ Structured Exception Handling。显然,可以检测到您的代码在SEH处理程序中运行,因为必须检测到ExceptionNestedException
。 TEB包含所需的一切,只要您是操作系统或调试器并知道如何解释它。
对于你,我强烈建议退回并沿着记录的路径前进。如果需要,将您的日志记录包装在try / catch块中,以避免从不抛出的代码中泄漏异常。确保正确处理ThreadAbortException
,因为特殊。通过适当的日志记录和错误报告,酌情加入Application.UnhandledException
,Application.ThreadException
和/或AppDomain.UnhandledException
。
答案 4 :(得分:0)
如其他答案所述,你不能。您可以通过将参数传递给方法来伪造它,但这似乎是代码味道。
答案 5 :(得分:0)
您可以随时轻松地完成这项工作:
void SomeFunction(bool isCalledFromCatch)
{
// how do I detect whether I am being called from within a catch block?
}
try
{
}
catch(...)
{
SomeFunction(true);
}