views:

225

answers:

3

Is there a way, how to get currently thrown exception (if exists)?

I would like reduce amount of code and apply some reuse for task looks like:

Exception thrownException = null;
try {
    // some code with 3rd party classes, which can throw unexpected exceptions
}
catch( Exception exc ) {
    thrownException = exc;
    LogException( exc );
}
finally {
    if ( null == thrownException ) {
        // some code
    }
    else {
        // some code
    }
}

and replace it with this code:

using( ExceptionHelper.LogException() ) {
    // some code with 3rd party classes, which can throw unexpected exceptions
}
using( new ExceptionHelper { ExceptionAction = ()=> /*some cleaning code*/ } ) {
    // some code with 3rd party classes, which can throw unexpected exceptions
}

public class ExceptiohHelper : IDisposable {
    public static ExceptionHelper LogException() {
        return new ExceptionHelper();
    }

    public Action SuccessfulAction {get; set;}
    public Action ExceptionAction {get; set;}

    public void Dispose() {
        Action action;
        Exception thrownException = TheMethodIDontKnow();
        if ( null != thrownException ) {
            LogException( thrownException );
            action = this.ExceptionAction;
        }
        else {
            action = this.SuccessfulAction;
        }

        if ( null != action ) {
            action();
        }
    }
}

Is this scenario posible?

Thanks

+3  A: 

The idea is that you handle exceptions in the catch block...

That said, Exception is a reference type, so you can always declare an Exception variable outside the try scope...

Exception dontDoThis;
try
{
    foo.DoSomething();
}
catch(Exception e)
{
    dontDoThis = e;
}
finally
{
    // use dontDoThis...
}
Mark Seemann
Yes, I know the way try-catch-finally. I use it now, as I said in the question - please read it one more time. But I want to reduce the writing code, and extend the reuse ability. This is not the answer in any way :(
TcKs
+2  A: 

If you are looking to catch unexpected exceptions you should be handling the UnhandledException. You should only catch exceptions at lower levels that you intend handle (not just to log), otherwise you should let them bubble up and be caught at a higher level, or as I mentioned before in the UnhandledException method.

James
The UnhandlerException is a global event, and I lost every context informations - it is useless for concrete exception-handling in different code. However, this is better answr than @Mark Seemann. Maybe there can be some way, how to dynamicelly attach/dettach the UnhandledException. I'll try it.
TcKs
The UnhandledException looks good, but if the exception is handled somewhere in caller code, the event is not raised (it makes sense - then is exception handled). But thanks, maybe I can found some "HandledException" event.
TcKs
If you still want your Exception to get handled in the UnhandledException but you want to deal with it internally, just handle it and then rethrow it.
James
I want skip try-catch-finally blocks, because there is no efective way, how-to reuse it in large projects and manage refactoring is very time consuming.The UnhandledException is raised only, if no catch-block is in above in stack trace. So if you have "void Main() { try { new Form1().ShowDialog(); } catch { ... }", the UnhandledException event is never fired.
TcKs
@Tcks...not true. The UnhandledException event is raised if you do not *handle* the raised exception. Unless of course you are catching Exception (the base class) to which I would say is bad design.
James
+1  A: 

What do you think about the following. Instead of looking at the problem as "How to get the last exception?", what if you change it to, "How do I run some piece of code with some more control?"

For example: Instead of an ExceptionHelper you could have an ActionRunner.

public class ActionRunner
{
    public Action AttemptAction { get; set; }
    public Action SuccessfulAction { get; set; }
    public Action ExceptionAction { get; set; }

    public void RunAction()
    {
        try
        {
            AttemptAction();
            SuccessfulAction();
        }
        catch (Exception ex)
        {
            LogException(ex);
            ExceptionAction();
        }
    }

    private void LogException(Exception thrownException) { /* log here... */ }
}

It would at least give you some reuse of the SuccessfulAction and ExceptionAction assuming only the AttemptAction varies between calls.

var actionRunner = new ActionRunner
{
    AttemptAction = () =>
    {
        Console.WriteLine("Going to throw...");
        throw new Exception("Just throwing");
    },
    ExceptionAction = () => Console.WriteLine("ExceptionAction"),
    SuccessfulAction = () => Console.WriteLine("SuccessfulAction"),
};
actionRunner.RunAction();

actionRunner.AttemptAction = () => Console.WriteLine("Running some other code...");
actionRunner.RunAction();
Kim Major
Yes! The "Template method" design pattern is solution.Thanks!
TcKs