Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch/Modify (Message)/Rethrow Exception of same type

I want a central place to extract information from an exception, set all the information I need to its message parameter and then rethrow that information as an Exception of the same type.

The better solution probably would be to do this at the place where the exception is finally being handled (and its message logged), but.. I have control over the place throwing the exception, and not over the place that receives the exception and only logs its Message content.

Apart from that design decision and given that message is a readonly property, I would have (?) to create a new Exception object in some way, is there a way to make the new exception object the same type as the original one?

Here is my code, which does not compile - it stumbles over the throw line (where I try to dynamically cast the object).

public static void RethrowExceptionWithFullDetailInMessage(string msg, Exception ex)
{
    Exception curEx = ex;
    int cnt = 0;
    while (curEx != null)
    {
        msg += "\r\n";
        msg += cnt++ + " ex.message: " + curEx.Message + "\r\n";
        msg += "Stack: " + curEx.StackTrace;
        curEx = curEx.InnerException;
    }
    object newEx = Convert.ChangeType(new Exception(msg), ex.GetType());
    throw (ex.GetType())newEx;
}

Does this

throw (Exception)newEx;

preserve the type? (It compiles.)

Does the Convert.ChangeType make sure I get an Exception of the correct type?

like image 913
Andreas Reiff Avatar asked Jul 26 '12 14:07

Andreas Reiff


2 Answers

What you are trying to do here is not as easy as it seems and there are lots of pitfalls to consider.

Remember, that Convert.ChangeType() will convert one type to another (assuming such a path exists, like converting a string to an int for example). Most exceptions wont do this (Why would they?)

IN order to pull this off, you would have to examine the exception type at runtime with the GetType() method and locate a constructor that has requirements you can satisfy and invoke it. Be careful here, since you don't have control over how all exceptions are defined there is no guarantee you will have access to "standard" constructors.

That being said, if you feel like being a rule breaker you could do something like this...

void Main()
{
    try
    {   
        throw new Exception("Bar");
    }
    catch(Exception ex)
    {
        //I spit on the rules and change the message anyway
        ex.GetType().GetField("_message", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, "Foo");
        throw ex;
    }
}
like image 113
iamkrillin Avatar answered Oct 13 '22 22:10

iamkrillin


You could do this to dynamically call the constructor of the exception type:

object newEx = Activator.CreateInstance(ex.GetType(), new object[] { msg });

Your original code would fail at runtime, because for Convert.ChangeType towork, the exception type would have to implement IConvertible and support conversion to the other exception type, which i doubt.

like image 33
Botz3000 Avatar answered Oct 13 '22 22:10

Botz3000