#c_sharp #net
Если я ловлю ошибку в методе, а затем в блоке catch делаю throw этой ошибки на верх, то в стеке ошибок пишется именно, что ошибочной строкой является throw. Можно ли как-то получить реальное место возникновения ошибки? Пример кода: static void Main(string[] args) { try { var t = 1; var t3 = 2; var t4 = t - t3; throw new Exception("BlaBla bla"); } catch (Exception ex) { throw; } } Тут у меня пишется, что исключение возникло не в throw new Exception("BlaBla bla"); , а на строчке с throw;
Ответы
Ответ 1
Делайте throw; // перебросить с оригинальным стектрейсом А не throw ex; // бросить заново и потерять стектрейс К сожалению, если исключение было брошено, поймано, и переброшено в одном и том же методе - строчка в стектрейсе поменяется даже в случае если был использован throw;. CLR использует SEH, а тот использует стекфремы для отслеживания цепочки вызовов. На один метод - один стекфрейм, так что перебрасывание исключения в рамках одного метода перетирает оригинальный stack trace. Т.е. любой метод бросания исключения - и throw;, и throw ex; - изменяют стектрейс. Просто первый сохраняет более глубокие фреймы, а второй - нет. Вопрос на английском: enSO: Incorrect stacktrace by rethrowОтвет 2
Это можно сделать на современном C#, хотя и не так изящно, как хотелось бы. Вам нужно поместить логику до throw в фильтр исключений, и вернуть из него false для случая, когда исключение нужно пробросить. При этом код вообще не будет заходить в catch. Вместо метода static void Main(string[] args) { var t = 1; try { var t3 = 2; var t4 = t - t3; throw new Exception("BlaBla bla"); } catch (Exception ex) { Console.WriteLine($"Exception with message {ex.Message} thrown, t = {t}"); throw; } } (тут в StackTrace только строка с throw) у вас получится вот такое: static void Main(string[] args) { var t = 1; try { var t3 = 2; var t4 = t - t3; throw new Exception("BlaBla bla"); } catch (Exception ex) when (Filter(ex)) { } bool Filter(Exception ex) { Console.WriteLine($"Exception with message {ex.Message} thrown, t = {t}"); return false; } } (в StackTrace только строка с throw new Exception("BlaBla bla");). Ещё один популярный (в узких кругах) вариант — использование System.Runtime.ExceptionServices.ExceptionDispatchInfo. Вот такой код: static void Main(string[] args) { var t = 1; try { var t3 = 2; var t4 = t - t3; throw new Exception("BlaBla bla"); } catch (Exception ex) { Console.WriteLine($"Exception with message {ex.Message} thrown, t = {t}"); ExceptionDispatchInfo.Capture(ex).Throw(); } } производит StackTrace из двух частей: at Test.Program.Main(String[] args) in ...\Program.cs:line 38 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Test.Program.Main(String[] args) in ...\Program.cs:line 43 Строка 38 содержит throw new Exception("BlaBla bla");, а строка 43 — ExceptionDispatchInfo.Capture(ex).Throw();. (Я вынес переменную t, чтобы к ней можно было обращаться из блока catch ну или из локальной функции.) Ограничение метода: невозможно использовать async-метод в фильтре. При большом желании, фильтр можно и заинлайнить. Синтаксис при этом становится совсем вырвиглазным.Ответ 3
Можно: try { ... } catch(ExceptionType ex) { throw; // а не throw ex; }
Комментариев нет:
Отправить комментарий