How to set the InnerException of custom Exception class from its constructor
C#.NetExceptionLoggingReflectionC# Problem Overview
How can I set the InnerException
property of an Exception
object, while I'm in the constructor of that object? This boils down to finding and setting the backing field of a property that has no setter.
BTW: I have seen this evain.net - Getting the field backing a property using Reflection but looking for non IL-based solution, if possible.
The constructor of Exception
is the place where the Exception
type is created, so I cannot call it using the base class constructor MyException() :base(...)
etc.
C# Solutions
Solution 1 - C#
You set the inner exception by calling the base ctor:
public MyException(string message, Exception innerException)
: base(message, innerException) {...}
If you need to run some code to get the exception, use a static method:
public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) {...}
static Exception GetInner(SomeData data) {...} // <===== your type creation here!
static string GetMessage(SomeData data) {...}
Solution 2 - C#
The Exception
class has an overloaded constructor accepting the inner exception as a parameter:
Exception exc = new Exception("message", new Exception("inner message"));
Is this what you are looking for?
Solution 3 - C#
Why can't you just call the constructor taking the InnerException as a parameter? If for some reason it's not possible, the backing field in System.Exception is:
private Exception _innerException;
I found it out using Redgate's Reflector. Using reflection I suppose you could set the inner exception.
Edit: In most cases it's not a good idea to access private fields via reflection, but I don't know enough about NT's case to know for sure if it's a good or bad idea.
Solution 4 - C#
Exception exceptionWithMoreInfo = new Exception("extra info", ex);
would be normal practice assuming you've trapped an exception to which you'd like to add more information before bubbling up.
Solution 5 - C#
If I understand your question you want to do something like this:
Exception ex = new Exception("test");
Exception innerEx = new Exception("inner");
ex.GetType().GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ex, innerEx);
If you are in the constructor of an object that inherits from Exception you would use this
instead of the first ex
.
But this may not be the best way to handle whatever it is you are trying to handle.
Solution 6 - C#
Isn't InnerException
supposed to be set when using the Exception(string, Exception)
constructor? I think it's by design that you can't change this otherwise but you can always defer to the appropriate constructor at construction time:
class MyException : Exception {
public MyException()
: base("foo", new Exception("bar"))
{
...
}
...
}
I think you shouldn't ever break the exception chain in your code since that usually leads to errors you will never find again.
Solution 7 - C#
Use Redgate's Reflector to find the field. I doubt the Exception implementation will ever change... But it is a risk!
Solution 8 - C#
I know I'm really late to the party, but I find that this works.
public class MyException: Exception
{
public void SetInnerException(Exception exception)
{
typeof(Exception)
.GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(this, exception);
}
}
The trick is to get the actual Exception
type's _innerException
field, and then set the inner exception value to your class instance (MyException
in this case).
This also works for variables.
Exception mainException = new Exception();
typeof(Exception)
.GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(mainException , new Exception("Something bad happened!"));
Solution 9 - C#
In my situation I used this code:
class Foo
{
void Bar(MyException myException = null)
{
try
{
SomeActions.Invoke();
}
catch (Exception ex)
{
if (myException != null)
{
// Here I regenerate my exception with a new InnerException
var regenMyException = (MyException)System.Activator.CreateInstance(myException.GetType(), myException.Message, ex);
throw regenMyException;
}
throw new FooBarException("Exception on Foo.Bar()", ex);
}
}
}
HTH someone ;).
Solution 10 - C#
Extension methods work well.
namespace MyNamespace
{
public static class ExceptionExtensions
{
public static void SetInnerException(this Exception exception, string innerExceptionMessage)
{
typeof(Exception)
.GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(exception, new Exception(innerExceptionMessage));
}
}
}
Then in your catch block when you want to add the inner exception:
try
{
throw new Exception("Main Message");
}
catch (Exception ex)
{
ex.SetInnerException("Inner Message");
throw;
}