Как передать исключение без сброса трассировки стека?

Это следующий вопрос для Есть ли разница между "throw" и "throw ex" ?

Есть ли способ извлечь новый метод обработки ошибок без сброса трассировки стека?

[EDIT] Я буду пытаться как "внутренний метод", так и другой ответ, предоставленный Earwicker, и посмотреть, какой из них можно лучше отработать, чтобы отметить ответ.

Ответ 1

Не уверен, если вы имеете в виду это, но мое предложение в вашем другом вопросе касалось этого.

Если ваш обработчик возвращает логическое значение, было ли обработано исключение или нет, вы можете использовать это в своем предложении catch:

catch (Exception ex) {
  if (!HandleException(ex)) {
    throw;
  }
}

Ответ 2

Да; Это свойство InnerException для.

catch(Exception ex)
{
    throw new YourExceptionClass("message", ex);
}

Это позволит вам добавить свою собственную логику, а затем бросить свой собственный класс исключений. StackTrace из экземпляра YourExceptionClass будет изнутри этого кодового блока, но исключение InnerException будет исключением, которое вы поймали, с ранее созданным StackTrace.

Ответ 3

В .NET Framework 4.5 теперь есть ExceptionDispatchInfo, который поддерживает этот точный сценарий. Он позволяет фиксировать полное исключение и перетаскивать его из другого места, не переписывая содержащуюся трассировку стека.

пример кода из-за запроса в комментарии

using System.Runtime.ExceptionServices;

class Test
{
    private ExceptionDispatchInfo _exInfo;

    public void DeleteNoThrow(string path)
    {
        try { File.Delete(path); }
        catch(IOException ex)
        {
            // Capture exception (including stack trace) for later rethrow.
            _exInfo = ExceptionDispatchInfo.Capture(ex);
        }
    }

    public Exception GetFailure()
    {
        // You can access the captured exception without rethrowing.
        return _exInfo != null ? _exInfo.SourceException : null;
    }

    public void ThrowIfFailed()
    {
        // This will rethrow the exception including the stack trace of the
        // original DeleteNoThrow call.
        _exInfo.Throw();

        // Contrast with 'throw GetFailure()' which rethrows the exception but
        // overwrites the stack trace to the current caller of ThrowIfFailed.
    }
}

Ответ 4

Вы не хотите создавать новое исключение с исходной трассировкой стека. Это вводит в заблуждение, поскольку эта трассировка стека не создала нового исключения.

Однако вы можете поместить исходное исключение в свое новое исключение как "InnerException". Будет ли это делать то, что вы ищете?

Ответ 5

Захватываете ли вы исключения, которые хотите затем фильтровать более тщательно, чтобы затем вы могли передумать, решите не обрабатывать их и не перезапустить их?

Если вы хотите быть очень осторожным в этом, это не очень хорошая идея. Лучше никогда не поймать исключение в первую очередь. Причина в том, что данный обработчик try/catch не должен принимать решение запускать вложенные блоки finally для исключений, которые он не ожидает увидеть. Например, если существует NullReferenceException, вероятно, очень плохая идея продолжить выполнение какого-либо кода, так как это, вероятно, вызовет другое подобное исключение. А блоки finally - это просто код, как и любой другой код. Как только исключение будет поймано в первый раз, будут выполнены любые блоки finally в стеке под try/catch, к тому времени это слишком поздно - может быть сгенерировано другое исключение, а это означает, что исходное исключение потеряны.

Это означает (в С#), что вы должны тщательно написать отдельный обработчик catch для всех типов исключений, которые вы хотите поймать. Это также означает, что вы можете фильтровать только по типу исключений. Это иногда очень тяжелый совет.

Должно быть возможно отфильтровывать исключения другими способами, но в С# это не так. Тем не менее, это возможно в VB.NET, и сам BCL использует это, имея небольшой код, написанный на VB.NET, поэтому он может фильтровать исключения более удобным способом.

Вот подробное объяснение с образцом кода VB.NET из блога команды CLR.

И вот мои два цента.