7

How do I detect when the currently-executing code is being called from within a catch block?

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

EDIT:

For those asking, I wanted to implement a class like this, never mind the error bubbling logic: On writing this code sample, I'm getting a compiler error "A throw statement with no arguments is not allowed outside of a catch clause" so that kinda destroys my idea anyway.

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?
    }
}
bboyle1234
  • 4,859
  • 2
  • 24
  • 29
  • 10
    You don't. And if you think you need to, you are doing something wrong. – Jon Aug 26 '14 at 14:13
  • 4
    throw new Exception(); and see what happens next :) Just kidding. – gilles emmanuel Aug 26 '14 at 14:14
  • 3
    Explain why you need this and we can solve this XY problem for you. Alternatively, make your method throw exceptions on demand by introducing a `bool throwIfNotFound` parameter or whatever it is you want to accomplish. A method should never rely on whoever calls it or how, that's what parameters are for. – CodeCaster Aug 26 '14 at 14:17
  • Can you can up with some [real] "sample" code to show us the reasoning behind your solution? Perhaps we can aid in finding a better solution – lboshuizen Aug 26 '14 at 14:17
  • 1
    I suppose the hacky `bool caught = true` is out of the question? – Yann Aug 26 '14 at 14:24
  • Edited the question to include more info, thanks everybody – bboyle1234 Aug 26 '14 at 14:27
  • So your actual question is _"How can I rethrow an exception without losing the stack trace?"_? Then see [In C#, how can I rethrow InnerException without losing stack trace?](http://stackoverflow.com/questions/57383/in-c-how-can-i-rethrow-innerexception-without-losing-stack-trace). – CodeCaster Aug 26 '14 at 14:29
  • You could also opt for a combination of `AppDomain.FirstChanceException` and `AppDomain.UnhandledException`. All that come through the first, but not the last, have been caught already. – Patrick Hofman Aug 26 '14 at 14:30
  • @CodeCaster, +1 for writing "A method should never rely on whoever calls it or how, that's what parameters are for." – bboyle1234 Aug 26 '14 at 14:33
  • If you're trying to have a common exception handler, you can write a method & call that from any `catch` clause. The `throw` by itself to rethrow the exception needs to be in the `catch` block, however. – Tony Vitabile Aug 26 '14 at 14:45
  • 1
    I strongly suggest that you tell us what you're trying to accomplish, because you are almost certainly headed down a very bad path. – John Saunders Aug 26 '14 at 14:51

6 Answers6

3

You don't. There is no way to know if, should you throw an exception, it would be caught or crash the program. You could potentially make a guess at compile time with a code analysis tool, but that wouldn't be an option while the code is running.

Servy
  • 202,030
  • 26
  • 332
  • 449
2

No, there is no way to do that.

There might be some sneaky way by analyzing the generated (IL) code, but I am pretty sure you don't want that.

This is the IL from a standard Console application catching an exception:

.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

If you can analyze that your current code (say it is at "OK") is inside that block you could extract the try ... catch block. This of course doesn't take calling other methods in account.

It also sounds like a ridiculous solution to the problem you have, so before you throw yourself in something you don't want, think over if you really want to do this.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
1

You asked the wrong question, my friend!

Most frameworks allow for uncaught exceptions to be handled by a particular method. WPF, C# webforms, asp, all of these have an "unhandled exception handling" routine you can hook in to in the application level.

For instance, normal C# forms apps use:

    Application.ThreadException += new ThreadExceptionEventHandler(MyCommonExceptionHandlingMethod)

private static void MyCommonExceptionHandlingMethod(object sender, ThreadExceptionEventArgs t)
{
    //Exception handling...
}

So you would just need to declare your exceptionmanager class, then have the class hooked into the exception handling, for instance:

    Application.ThreadException += new ThreadExceptionEventHandler(TellMyClass)

private static void TellMyClass(object sender, ThreadExceptionEventArgs t)
{
     ExceptionManager.HandleException(sender, t);
}

However, the pattern I've used is:

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);
            }
        }
}

Which is used in the Program.cs:

public static void Main(){
  UnhandledExceptionManager.RegisterToHandleFormsException();
  //etc
}
C Bauer
  • 5,003
  • 4
  • 33
  • 62
1

CLR exceptions on Windows are just another SEH. Read the classic: A Crash Course on the Depths of Win32™ Structured Exception Handling. Obviously it is possible to detect that your code runs during a SEH handler, since ExceptionNestedException must be detected. The TEB contains everything needed, provided you you are the OS or a debugger and know how to interpret it.

For you, I would strongly recommend to back off and go down the documented path. If needed, wrap your logging in try/catch blocks to avoid leaking exceptions from code that is required to not throw. Make sure you handle ThreadAbortException properly since is so special. Hook into Application.UnhandledException, Application.ThreadException and/or AppDomain.UnhandledException, as appropriate, with proper logging and error reporting.

Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569
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.

David Crowell
  • 3,711
  • 21
  • 28
0

You can always do it the easy way:

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

try
{
}
catch(...)
{
    SomeFunction(true);
}
rhughes
  • 9,257
  • 11
  • 59
  • 87