Как установить InnerException для объекта.NET Exception
Как я могу установить свойство InnerException
объекта Exception
, пока я нахожусь в конструкторе этого объекта? Это сводится к нахождению и настройке вспомогательного поля свойства, которое не имеет установщика.
Кстати, я видел это evain.net - Получение поля, поддерживающего свойство с помощью Reflection, но поиск решения, не основанного на IL, если это возможно.
Конструктор Exception
- это место, где создается тип Exception
, поэтому я не могу вызвать его с помощью конструктора базового класса MyException() :base(...)
и т.д.
Ответы
Ответ 1
Почему вы не можете просто вызвать конструктор, который принимает значение InnerException в качестве параметра? Если по какой-то причине это невозможно, поле поддержки в System.Exception:
private Exception _innerException;
Я нашел это, используя Redgate Reflector. Используя отражение, я полагаю, вы можете установить внутреннее исключение.
Изменить: В большинстве случаев нецелесообразно обращаться к закрытым полям с помощью рефлексии, но я не знаю достаточно о случае NT, чтобы точно знать, является ли это хорошей или плохой идеей.
Ответ 2
Вы устанавливаете внутреннее исключение, вызывая базовый ctor:
public MyException(string message, Exception innerException)
: base(message, innerException) {...}
Если вам нужно запустить некоторый код для получения исключения, используйте статический метод:
public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) {...}
static Exception GetInner(SomeData data) {...} // <===== your type creation here!
static string GetMessage(SomeData data) {...}
Ответ 3
Класс Exception
имеет перегруженный конструктор, принимающий внутреннее исключение в качестве параметра:
Exception exc = new Exception("message", new Exception("inner message"));
Это то, что вы ищете?
Ответ 4
Exception exceptionWithMoreInfo = new Exception("extra info", ex);
будет обычной практикой, предполагая, что вы захватили исключение, к которому вы хотели бы добавить дополнительную информацию, прежде чем пузыриться.
Ответ 5
Если я понимаю ваш вопрос, вы хотите сделать что-то вроде этого:
Exception ex = new Exception("test");
Exception innerEx = new Exception("inner");
ex.GetType().GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ex, innerEx);
Если вы находитесь в конструкторе объекта, который наследует от Exception, вы должны использовать this
вместо первого ex
.
Но это может быть не лучший способ справиться с тем, что вы пытаетесь обработать.
Ответ 6
Не предполагается ли InnerException
при использовании конструктора Exception(string, Exception)
? Я думаю, что по дизайну вы не можете изменить это иначе, но вы всегда можете отнестись к соответствующему конструктору во время построения:
class MyException : Exception {
public MyException()
: base("foo", new Exception("bar"))
{
...
}
...
}
Я думаю, вы никогда не должны прерывать цепочку исключений в своем коде, поскольку это обычно приводит к ошибкам, которые вы больше никогда не найдете.
Ответ 7
С помощью Refgate Reflector найдите поле. Я сомневаюсь, что реализация Exception никогда не изменится... Но это риск!
Ответ 8
Я знаю, что я очень опаздываю на вечеринку, но считаю, что это работает.
public class MyException: Exception
{
public void SetInnerException(Exception exception)
{
typeof(Exception)
.GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(this, exception);
}
}
Фокус в том, чтобы получить фактическое поле Exception
type _innerException
, а затем установить значение внутреннего исключения для вашего экземпляра класса (MyException
в этом случае).
Это также работает для переменных.
Exception mainException = new Exception();
typeof(Exception)
.GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(mainException , new Exception("Something bad happened!"));
Ответ 9
В моей ситуации я использовал этот код:
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 кто-то;).