что может привести к сбросу стоп-кадра (я использую «throw», а не «throw ex»)
Я всегда считал, что разница между «throw» и «throw ex» заключалась в том, что бросок в одиночку не возвращал значение stacktrace исключения.
К сожалению, это не то поведение, которое я испытываю; вот простой пример, воспроизводящий мою проблему:
using System; using System.Text; namespace testthrow2 { class Program { static void Main(string[] args) { try { try { throw new Exception("line 14"); } catch (Exception) { throw; // line 18 } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.ReadLine(); } } }
Я ожидаю, что этот код напечатает стоп-стол, начиная с строки 14; однако столбец начинается с строки 18. Конечно, это не имеет большого значения в выборке, но в моем реальном приложении, потеря исходной информации об ошибке довольно болезненна.
- Вызов удаления по переменной, выделенной в стеке
- Распределение памяти: стек против кучи?
- Как вернуться к последней запущенной деятельности при повторном запуске приложения после нажатия HOME?
- Как resize стека для .NET-программы?
- c ++ Vector, что происходит, когда он расширяется / перераспределяется в стеке?
Мне что-то не хватает? Есть ли другой способ достичь того, что я хочу (т. Е. Повторно бросать исключение, не теряя информацию о стеке?)
Я использую .net 3.5
- В чем разница между ошибкой сегментации и переполнением стека?
- Как реализовать очередь с использованием двух стеков?
- Анализ Escape в Java
- Java / Android - Как распечатать полную трассировку стека?
- Как увеличить размер стека Java?
- Как предотвратить создание объекта в куче?
- Ошибка Weird MSC 8.0: «Значение ESP не было должным образом сохранено в вызове функции ...»
- Переполнение стека из глубокой рекурсии в Java?
Вы должны прочитать эту статью:
- Исключение исключений и сохранение полной стека стека вызовов
Короче говоря, throw
обычно сохраняет трассировку стека исходного исключенного исключения, но только если исключение не произошло в текущем фрейме стека (т.е. метод).
Существует метод PreserveStackTrace
(показан в этой статье в блоге), который вы используете, который сохраняет исходную трассировку стека следующим образом:
try { } catch (Exception ex) { PreserveStackTrace(ex); throw; }
Но мое обычное решение состоит в том, чтобы просто не перехватывать и повторять исключения вроде этого (если это абсолютно необходимо), или просто всегда бросать новые исключения, используя свойство InnerException
для распространения исходного исключения:
try { } catch (Exception ex) { throw new Exception("Error doing foo", ex); }
Проблема в том, что Windows сбрасывает исходную точку стека. CLR ведет себя как ожидалось – это просто ограничение поддержки обработки исключений операционной системы хоста. Проблема в том, что на вызов метода может быть только один стек.
Вы могли бы извлечь ваши процедуры обработки исключений в отдельный «вспомогательный» метод, который будет работать с ограничениями, наложенными Windows SEH, но я не думаю, что это обязательно хорошая идея.
Правильный способ повторного исключения исключений без потери информации о стеке – это выбросить новое исключение и включить исходное исключенное исключение в качестве внутреннего исключения.
Трудно представить себе очень много случаев, когда вам действительно нужно это делать. Если вы не обрабатываете исключение и просто ловите его, чтобы восстановить его, вы, вероятно, не должны его ловить.
Нормальный ретрон сохраняет все в трассировке стека за исключением того, что если данный метод находится в трассировке стека, номер строки будет перезаписан. Это раздражает поведение. В C #, если нужно что-то сделать в исключительном случае, но все равно, что такое исключение, можно использовать шаблон:
Boolean ok = False; пытаться { сделай что-нибудь(); ok = True; } в конце концов { if (! ok) // Произошло исключение! handle_exception (); }
Есть ряд, где эта схема очень полезна; наиболее распространенной будет функция, которая должна возвращать новый IDisposable. Если функция не вернется, одноразовый объект должен быть очищен. Обратите внимание, что любые операторы «return» в вышеуказанном блоке «try» должны установить ok в true .
В vb.net можно использовать шаблон, который функционально немного приятнее, хотя одно место в коде немного нехорошо, с шаблоном:
Dim PendingException As Exception = Nothing; Пытаться Сделай что-нибудь PendingException = Nothing 'См. Примечание Catch Ex As Exception Когда CopyFirstParameterToSecondAndReturnFalse (Ex, PendingException) Throw 'никогда не выполнится, так как выше вернет false в заключение Если PendingException IsNot Nothing Then Исключение Handle EndIf Конец Попробуйте
Долгосрочная функция должна быть реализована очевидным образом. Преимущество этого шаблона состоит в том, чтобы сделать исключение доступным для кода. Хотя это часто не требуется в ситуациях с ручкой, но не в сети, есть одна ситуация, когда это может быть неоценимым: если процедура очистки выдает исключение. Обычно, если процедура очистки генерирует исключение, любое ожидающее исключение будет потеряно. Однако с помощью вышеприведенного шаблона можно исключить ожидающее исключение в исключение очистки.
Одна интересная заметка с приведенным выше кодом: возможно, что исключение достигло «Catch When», но все же для завершения инструкции Try. В самом деле непонятно, что должно произойти в этом случае, но ясно одно, что оператор «Окончание» не должен действовать так, как если бы исключение ожидало. Очистка PendingException сделает так, что если исключение исчезнет, код будет вести себя так, как будто этого не произошло. Альтернативой было бы обернуть и перебросить исключение, которое, как известно, произошло, поскольку эта ситуация почти наверняка указывает на что-то неправильное с внутренним кодом обработки исключений.