在catch块内运行时检测

时间:2014-08-26 14:11:20

标签: c# catch-block

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

6 个答案:

答案 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处理程序中运行,因为必须检测到ExceptionNestedExceptionTEB包含所需的一切,只要您是操作系统或调试器并知道如何解释它。

对于你,我强烈建议退回并沿着记录的路径前进。如果需要,将您的日志记录包装在try / catch块中,以避免从不抛出的代码中泄漏异常。确保正确处理ThreadAbortException,因为特殊。通过适当的日志记录和错误报告,酌情加入Application.UnhandledExceptionApplication.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);
}