Я смотрю на статью C # - Объект передачи данных о сериализуемых DTO.
Статья включает в себя этот кусок кода:
public static string SerializeDTO(DTO dto) {
try {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
catch(Exception ex) {
throw ex;
}
}
Остальная часть статьи выглядит вменяемой и разумной (нубу), но этот try-catch-throw создает исключение WtfException ... Разве это не эквивалентно тому, чтобы вообще не обрабатывать исключения?
Ergo:
public static string SerializeDTO(DTO dto) {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
Или я упускаю что-то фундаментальное в обработке ошибок в C #? Это почти так же, как Java (за исключением проверенных исключений), не так ли? ... То есть они оба усовершенствовали C ++.
Вопрос переполнения стека Разница между перебросом улова без параметров и бездействием? кажется, поддерживает мое утверждение о том, что try-catch-throw это неоперация.
РЕДАКТИРОВАТЬ:
Просто подвести итог для тех, кто найдет эту тему в будущем ...
НЕ ДЕЛАЙТЕ
try {
// Do stuff that might throw an exception
}
catch (Exception e) {
throw e; // This destroys the strack trace information!
}
Информация трассировки стека может иметь решающее значение для выявления первопричины проблемы!
ДЕЛАТЬ
try {
// Do stuff that might throw an exception
}
catch (SqlException e) {
// Log it
if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
// Do special cleanup, like maybe closing the "dirty" database connection.
throw; // This preserves the stack trace
}
}
catch (IOException e) {
// Log it
throw;
}
catch (Exception e) {
// Log it
throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
// Normal clean goes here (like closing open files).
}
Поймать более конкретные исключения, прежде чем менее конкретные (так же, как Java).
Ссылки:
источник
Ответы:
Первый; способ, которым код в статье делает это, является злом.
throw ex
сбросит стек вызовов в исключении до точки, где находится этот оператор throw; потерять информацию о том, где на самом деле было создано исключение.Во-вторых, если вы просто поймаете и перебросите таким образом, я не вижу никакой дополнительной ценности, приведенный выше пример кода был бы таким же хорошим (или, учитывая
throw ex
бит, даже лучше) без try-catch.Однако есть случаи, когда вы можете захотеть перехватить и выбросить исключение. Регистрация может быть одним из них:
источник
ex
объект, тогда нет необходимости создавать его экземпляр.throw ex
не перезапускается трассировка стека.Не делай этого,
Вы потеряете информацию трассировки стека ...
Либо делай,
ИЛИ
Одна из причин, по которой вы можете захотеть сбросить, - это если вы обрабатываете разные исключения, например,
источник
C # (до C # 6) не поддерживает CIL «отфильтрованные исключения», что делает VB, поэтому в C # 1-5 одной из причин для повторного выброса исключения является то, что у вас недостаточно информации во время catch () чтобы определить, хотите ли вы на самом деле поймать исключение.
Например, в VB вы можете сделать
... который не будет обрабатывать MyExceptions с различными значениями ErrorCode. В C # до v6 вам пришлось бы перехватывать и перебрасывать MyException, если ErrorCode не был 123:
Начиная с C # 6.0 вы можете фильтровать, как с VB:
источник
Моя главная причина для того, чтобы иметь такой код:
так что я могу иметь точку останова в catch, который имеет экземпляр объекта исключения. Я делаю это много во время разработки / отладки. Конечно, компилятор предупреждает меня обо всех неиспользованных е, и в идеале они должны быть удалены перед сборкой релиза.
Они хороши во время отладки.
источник
#if DEBUG
вокруг ОБАtry {
и} catch () {...}
немного грязный и, честно говоря, делает меня тошнило ... Предварительно процессор, вообще говоря, не мой друг.Действительная причина для повторного выброса исключений может заключаться в том, что вы хотите добавить информацию об исключении или, возможно, обернуть исходное исключение одним из ваших собственных решений:
источник
Не совсем, это не то же самое. Сбрасывает трассировку стека исключения. Хотя я согласен, что это, вероятно, ошибка, и, следовательно, пример плохого кода.
источник
Вы не хотите бросать ex - так как это потеряет стек вызовов. См. Обработка исключений (MSDN).
И да, команда try ... catch не делает ничего полезного (кроме потери стека вызовов - так что на самом деле это еще хуже - если только по какой-то причине вы не захотели раскрыть эту информацию).
источник
Вопрос, который люди не упомянули, заключается в том, что, хотя языки .NET на самом деле не проводят должного различия, вопрос о том, следует ли предпринимать какие-либо действия при возникновении исключения и разрешает ли он его, на самом деле является отдельным вопросом. Во многих случаях нужно предпринимать действия, основанные на исключениях, которые не имеют надежды на разрешение, и в некоторых случаях все, что необходимо для «разрешения» исключения, - это размотать стек до определенной точки - никаких дальнейших действий не требуется. ,
Из-за общей мудрости, что нужно «ловить» только то, с чем можно «справиться», большой код, который должен действовать при возникновении исключений, этого не делает. Например, большая часть кода получает блокировку, «временно» помещает охраняемый объект в состояние, которое нарушает его инварианты, затем переводит его в законное состояние и затем снимает блокировку, прежде чем кто-либо еще сможет увидеть объект. Если возникает исключение, когда объект находится в опасно недопустимом состоянии, обычной практикой является снятие блокировки с объектом, все еще находящимся в этом состоянии. Гораздо лучше было бы иметь исключение, которое возникает, когда объект находится в «опасном» состоянии, и недействительно блокирует блокировку, поэтому любая будущая попытка получить ее немедленно потерпит неудачу.
В большинстве языков .NET единственным способом, позволяющим коду выполнить действие, основанное на исключении, является
catch
его (даже если он знает, что исключение не будет устранено), выполнить соответствующее действие и затем повторно выполнитьthrow
). Другой возможный подход, если коду не важно, какое исключение выдается, это использоватьok
флаг сtry/finally
блоком; установитеok
флагfalse
перед блоком, иtrue
до выхода из блока, и перед любым,return
который находится внутри блока. Затем, внутриfinally
, предположим, что еслиok
не установлено, должно произойти исключение. Такой подход семантически лучше, чемcatch
/throw
, но уродлив и менее ремонтопригоден, чем должен быть.источник
Это может быть полезно, когда ваши функции программирования для библиотеки или DLL.
Эту структуру повторного вызова можно использовать для целенаправленного сброса стека вызовов, чтобы вместо просмотра исключения, генерируемого отдельной функцией внутри функции, вы получали исключение из самой функции.
Я думаю, что это просто используется, чтобы выброшенные исключения были чище и не уходили в «корни» библиотеки.
источник
Одна из возможных причин броска - это отключение любых фильтров исключений, расположенных выше в стеке ( случайная старая ссылка ). Но, конечно, если бы это было намерение, там был бы комментарий, говорящий так.
источник
Это зависит от того, что вы делаете в блоке catch, и хотите ли вы передать ошибку вызывающему коду или нет.
Вы могли бы сказать,
Catch io.FileNotFoundExeption ex
а затем использовать альтернативный путь к файлу или что-то подобное, но все равно выдать ошибку.Кроме того, выполнение
Throw
вместоThrow Ex
позволяет сохранить полный след стека. Throw ex перезапускает трассировку стека из оператора throw (надеюсь, это имеет смысл).источник
В то время как многие другие ответы предоставляют хорошие примеры того, почему вы можете захотеть перехватить исключение, похоже, никто не упомянул сценарий «наконец».
Примером этого является то, что у вас есть метод, в котором вы устанавливаете курсор (например, курсор ожидания), у метода есть несколько точек выхода (например, if () return;), и вы хотите убедиться, что курсор сброшен при конец метода.
Для этого вы можете обернуть весь код в try / catch / finally. В конце установите курсор обратно на правый курсор. Чтобы вы не хоронили никаких действительных исключений, сбросьте их в улов.
источник
catch
ли обязательная частьtry...finally
исторически или она играет функциональную роль в этом примере? - Я просто дважды проверил, и я могу использоватьtry {} finally {}
вообще без блока catch.В примере из кода, который вы опубликовали, фактически нет смысла перехватывать исключение, поскольку ничего не сделано для перехвата, который он просто повторяет, фактически он приносит больше вреда, чем пользы, так как стек вызовов потерян ,
Однако вы бы поймали исключение, чтобы выполнить некоторую логику (например, закрытие sql-соединения блокировки файла или просто некоторая регистрация) в случае исключения и выбросить его обратно в вызывающий код для обработки. Это было бы более распространенным на бизнес-уровне, чем код переднего плана, так как вы можете захотеть, чтобы кодер, реализующий ваш бизнес-уровень, обрабатывал исключение.
Повторить, хотя нет смысла поймать исключение в примере, который вы опубликовали. НЕ делай так!
источник
Извините, но многие примеры «улучшенного дизайна» до сих пор пахнут ужасно или могут вводить в заблуждение. Попробовав {} catch {log; throw} просто совершенно бессмысленно. Регистрация исключений должна выполняться в центральном месте внутри приложения. в любом случае исключения заполняют трассировку стека, почему бы не записать их где-нибудь вверх и близко к границам системы?
Следует соблюдать осторожность при сериализации вашего контекста (например, DTO в одном из приведенных примеров) только в сообщении журнала. Он может легко содержать конфиденциальную информацию, которая может не попасть в руки всех людей, которые могут получить доступ к файлам журнала. И если вы не добавите новую информацию в исключение, я действительно не вижу смысла в исключении. У старой доброй Java есть кое-что для этого, она требует, чтобы вызывающая сторона знала, какие исключения следует ожидать, затем вызывая код. Так как в .NET этого нет, обертывание не приносит пользы, по крайней мере, в 80% случаев, которые я видел.
источник
В дополнение к тому, что сказали другие, см. Мой ответ на связанный вопрос, который показывает, что перехват и перебрасывание не запрещены (это в VB, но часть кода может быть вызвана из C # из VB).
источник
Большинство ответов говорят о сценарии catch-log-rethrow.
Вместо того, чтобы писать это в своем коде, рассмотрите возможность использования AOP, в частности Postsharp.Diagnostic.Toolkit с OnExceptionOptions IncludeParameterValue и IncludeThisArgument
источник
Возврат исключений через
throw
полезно, когда у вас нет конкретного кода для обработки текущих исключений или в случаях, когда у вас есть логика для обработки определенных случаев ошибок, но вы хотите пропустить все остальные.Пример:
Однако есть и другой способ сделать это, используя условные предложения в блоках catch:
источник