7

如何检测何时从 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?
    }
}
4

6 回答 6

3

你没有。没有办法知道,如果你抛出一个异常,它是否会被捕获或使程序崩溃。您可能使用代码分析工具在编译时进行猜测,但在代码运行时这不是一个选项。

于 2014-08-26T14:14:09.313 回答
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块。这当然不考虑调用其他方法。

这听起来也像是解决您遇到的问题的荒谬方法,因此,在您将自己投入到您不想要的事情之前,请考虑一下您是否真的想这样做。

于 2014-08-26T14:18:59.643 回答
1

Windows上的CLR 异常只是另一个 SEH。阅读经典:Win32™ 结构化异常处理深度速成课程。显然,可以检测到您的代码在 SEH 处理程序期间运行,因为ExceptionNestedException必须检测到。TEB包含所需的一切,前提是您是操作系统或调试器并且知道如何解释它。

对你来说,我强烈建议你退后一步,沿着记录在案的路径走下去。如果需要,请将您的日志记录在 try/catch 块中,以避免从需要不抛出的代码中泄漏异常。确保你处理ThreadAbortException得当,因为它是如此特别。使用适当的日志记录和错误报告连接到Application.UnhandledException,Application.ThreadException和/或。AppDomain.UnhandledException

于 2014-08-26T14:44:53.597 回答
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
}
于 2014-08-26T14:30:49.987 回答
0

你总是可以用简单的方法做到这一点:

void SomeFunction(bool isCalledFromCatch)
{
    // how do I detect whether I am being called from within a catch block?
}

try
{
}
catch(...)
{
    SomeFunction(true);
}
于 2014-08-26T15:05:32.407 回答
0

As stated in the other answers, you can't. You can fake it by passing a parameter to the method, but that seems to be a code smell.

于 2014-08-26T14:33:09.197 回答