Подтвердить что ты не робот

Как установить InnerException для объекта.NET Exception

Как я могу установить свойство InnerException объекта Exception, пока я нахожусь в конструкторе этого объекта? Это сводится к нахождению и настройке вспомогательного поля свойства, которое не имеет установщика.

Кстати, я видел это evain.net - Получение поля, поддерживающего свойство с помощью Reflection, но поиск решения, не основанного на IL, если это возможно.

Конструктор Exception - это место, где создается тип Exception, поэтому я не могу вызвать его с помощью конструктора базового класса MyException() :base(...) и т.д.

4b9b3361

Ответ 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 кто-то;).