Detect when running inside a catch block
Asked Answered
P

6

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?
    }
}
Piffle answered 26/8, 2014 at 14:11 Comment(11)
You don't. And if you think you need to, you are doing something wrong.Fortuitism
throw new Exception(); and see what happens next :) Just kidding.Guitarfish
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.Sooth
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 solutionRocco
I suppose the hacky bool caught = true is out of the question?Cardamom
Edited the question to include more info, thanks everybodyPiffle
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?.Sooth
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.Foreboding
@CodeCaster, +1 for writing "A method should never rely on whoever calls it or how, that's what parameters are for."Piffle
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.Retrogress
I strongly suggest that you tell us what you're trying to accomplish, because you are almost certainly headed down a very bad path.Hectograph
S
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.

Spitler answered 26/8, 2014 at 14:14 Comment(0)
F
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.

Foreboding answered 26/8, 2014 at 14:18 Comment(0)
G
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
}
Groscr answered 26/8, 2014 at 14:30 Comment(0)
U
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.

Upas answered 26/8, 2014 at 14:44 Comment(0)
D
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.

Deserted answered 26/8, 2014 at 14:33 Comment(0)
R
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);
}
Roth answered 26/8, 2014 at 15:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.