在抓块内运行时进行检测
本文关键字:检测 运行时 | 更新日期: 2023-09-27 18:19:37
如何检测当前执行的代码何时从catch块中被调用?
void SomeFunction()
{
// how do I detect whether I am being called from within a catch block?
}
编辑:
对于那些提问的人,我想实现这样一个类,更不用说错误冒泡逻辑了:在编写这个代码示例时,我收到了一个编译器错误"catch子句之外不允许使用没有参数的throw语句",所以这有点破坏了我的想法。
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?
}
}
您没有。如果抛出异常,则无法知道它是否会被捕获或使程序崩溃。您可以在编译时使用代码分析工具进行猜测,但在代码运行时,这不是一个选项。
不,没有办法做到这一点。
可能有一些偷偷摸摸的方法来分析生成的(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
块。这当然不考虑调用其他方法。
这听起来也是一个荒谬的解决方案,所以在你投入到你不想要的事情中之前,仔细想想你是否真的想这样做。
我的朋友,你问错了问题!
大多数框架都允许通过特定的方法来处理未捕获的异常。WPF、C#Web窗体、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);
}
}
}
程序中使用的.cs:
public static void Main(){
UnhandledExceptionManager.RegisterToHandleFormsException();
//etc
}
CLR异常在Windows上只是另一个SEH。阅读经典:Win32深度速成课程™结构化异常处理。显然,可以检测到代码在SEH处理程序中运行,因为必须检测到ExceptionNestedException
。TEB包含所需的一切,前提是你是操作系统或调试器,并且知道如何解释它
对你来说,我强烈建议你放弃,走记录在案的道路。如果需要,请将日志记录封装在try/catch块中,以避免从要求不抛出的代码中泄漏异常。请确保正确处理ThreadAbortException
,因为它非常特殊。根据需要挂接Application.UnhandledException
、Application.ThreadException
和/或AppDomain.UnhandledException
,并进行适当的日志记录和错误报告。
如其他答案所述,您不能。您可以通过向方法传递参数来伪造它,但这似乎是一种代码气味。
你总是可以用简单的方法:
void SomeFunction(bool isCalledFromCatch)
{
// how do I detect whether I am being called from within a catch block?
}
try
{
}
catch(...)
{
SomeFunction(true);
}