在抓块内运行时进行检测

本文关键字:检测 运行时 | 更新日期: 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.UnhandledExceptionApplication.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);
}