Как вызвать исключение без сброса трассировки стека? - PullRequest
19 голосов
/ 08 апреля 2009

Это дополнительный вопрос к Есть ли разница между «throw» и «throw ex» ?

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

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

Ответы [ 5 ]

43 голосов
/ 08 апреля 2009

Да; Для этого и используется свойство InnerException.

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

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

39 голосов
/ 27 сентября 2012

В .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.
    }
}
26 голосов
/ 08 апреля 2009

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

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

catch (Exception ex) {
  if (!HandleException(ex)) {
    throw;
  }
}
5 голосов
/ 08 апреля 2009

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

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

2 голосов
/ 08 апреля 2009

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

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

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

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

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

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

...