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

I want to get a central place to extract information from an exception, set all the information I need into its message parameter, and then reinstall this information as an exception of the same type.

The best solution would probably be to do it in the place where the exception is finally handled (and its message is logged), but .. I have control over the place that throws the exception, and not over the place that receives the exception and only logs its message content.

Besides this constructive decision and considering that the message is a readonly property, I would (?) Somehow create a new Exception object, is there a way to make the new exception object the same type as the original

Here is my code that does not compile - it stumbles upon a throw line (where I am trying to dynamically drop an 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; } 

it

 throw (Exception)newEx; 

save type? (It compiles.)

Does Convert.ChangeType set that I get an exception from the correct type?

+7
source share
5 answers

What you are trying to do here is not as simple as it seems, and there are many pitfalls to consider.

Remember that Convert.ChangeType () converts one type to another (assuming that such a path exists, for example, converting a string to int). Most exceptions will not do this (why are they?)

To distract this, you will need to examine the type of exception at runtime using the GetType () method and find a constructor that has requirements that you can satisfy and call. Be careful, since you do not control how all exceptions are defined, there is no guarantee that you will have access to "standard" constructors.

If you want you to be a rulebreaker, 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; } } 
+11
source

You can do this to dynamically call an exception type constructor:

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

The source code will not work at runtime because for Convert.ChangeType towork the exception type must implement IConvertible and support conversion to another type of exception, which I doubt.

+4
source

It may be a little late, but will it work for you?

 catch (Exception ex) { throw new Exception("New message", ex); } 
+3
source

You can change the exception message through reflection like this ...

 Exception exception = new Exception("Some message."); var type = typeof(Exception); var flags = BindingFlags.Instance | BindingFlags.NonPublic; var fieldInfo = type.GetField("_message", flags); fieldInfo.SetValue(exception, message); 

That way you can create an extension method ...

 namespace ExceptionExample { public static class ExceptionExtensions { public static void SetMessage(this Exception exception, string message) { if (exception == null) throw new ArgumentNullException(nameof(exception)); var type = typeof(Exception); var flags = BindingFlags.Instance | BindingFlags.NonPublic; var fieldInfo = type.GetField("_message", flags); fieldInfo.SetValue(exception, message); } } } 

And then use this ...

 ... using static ExceptionExample.ExceptionExtensions; public class SomeClass { public void SomeMethod() { var reader = AnotherClass.GetReader(); try { reader.Read(); } catch (Exception ex) { var connection = reader?.Connection; ex.SetMessage($"The exception message was replaced.\n\nOriginal message: {ex.Message}\n\nDatabase: {connection?.Database}"); throw; // you will not lose the stack trace } } } 

You should keep in mind that if you use throw ex; stack trace will be lost .

To avoid this, you should use "throw;" without exception .

0
source

Additional comment.

This all works in addition to the exception message, but I found that using the throw command does NOT save StackTrace - the last trace points to the actual throw statement (removing the root cause location).

From discussions elsewhere, it is clear that there are some circumstances that throw does not preserve due to CLR stack restrictions

Throwing and saving the stack trace is not as expected, as described in Code Analysis

Solution: flush StackTrace in each exception (for example, add to error message) and / or flush to log

0
source

All Articles