views:

336

answers:

7

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.

If your answer is this cannot be done, don't answer please!

I'm saying this because it should be possible via reflection, so if you know how to do it, please enlighten me.

btw: I have seen this (http://evain.net/blog/articles/2009/05/01/getting-the-field-backing-a-property-using-reflection) but looking for non IL-based solution, if possible.


Thanks for the initial input, but I should have clarified that the Exception constructor is the place where the Exception type is created, so I cannot call it using the base class constructor MyException() :base(...) etc.

This is why I'm looking into attempting to alter the backing field via reflection, as the property is get only.

+1  A: 
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.

dove
This doesn't help you in the exception's ctor, though.
Joey
+12  A: 

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) {...}
Marc Gravell
A: 

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.

Joey
A: 

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?

Paolo Tedesco
+1  A: 

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.

Meta-Knight
I can't think of a sensible example where reflection is the right way to do this...
Marc Gravell
It makes sense for dynamic scenarios involving activations of exceptions where the inner exception cannot be known in advance, therefore cannot be passed to the constructor.
No, it doesn't. It really doesn't; it breaks encapsulation. Use a static method in the ` : base(SomeMethod(...), ...)` chain.
Marc Gravell
@_NT: For the inner exception to make sense it should occur before the current exception. Typically you want to bubble exceptions up... not down.
Matthew Whited
BTW... changing private and internal values with reflection may cause breaking changes in the future. If you do this it's at your own risk.
Matthew Whited
+1  A: 

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.

Paulo Manuel Santos
What's wrong with Exception innerEx = new Exception("inner"); Exception ex = new Exception("test", innerEx); ?
John Saunders
He is trying to modify the object ex which was not created in the context, I create it just for the purpose of demoing. Actually in his case he is trying to modify the this instance.
Paulo Manuel Santos
+1: This answered my own rather silly question of how to force an exception's inner exception to be itself, thus causing fun things like having the ToString() method trigger a stack overflow.
Brian
+1  A: 

Use Redgate's Reflector to find the field. I doubt the Exception implementation will ever change... But it is a risk!

_NT
Why would you doubt this? What basis do you have for making this assessment? If I were Microsoft, I'd change the implementation just to spite fools who depend on internal implementation details of other people's classes.
John Saunders
Based on the amount of such details that have changed over the past framework updates?
_NT
@John: Good thing you're not working for MS then!
Scooterville