какая разница между
try { ... }
catch{ throw }
и
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Независимо от того, что второе показывает сообщение?
какая разница между
try { ... }
catch{ throw }
и
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Независимо от того, что второе показывает сообщение?
throw;
восстанавливает исходное исключение и сохраняет исходную трассировку стека.
throw ex;
выдает исходное исключение, но сбрасывает трассировку стека, уничтожая всю информацию о трассировке стека до вашего блока catch
.
throw ex;
throw new Exception(ex.Message);
еще хуже. Он создает новый экземпляр Exception
, теряющий исходную трассировку стека исключения, а также его тип. (например, IOException
).
Кроме того, некоторые исключения содержат дополнительную информацию (например, ArgumentException.ParamName
). throw new Exception(ex.Message);
также уничтожит эту информацию.
В некоторых случаях вы можете обернуть все исключения в настраиваемом объекте исключений, чтобы вы могли предоставить дополнительную информацию о том, что делает код при возникновении исключения.
Чтобы сделать это, определите новый класс, наследующий Exception
, добавить все четыре конструктора исключений, и необязательно дополнительный конструктор, который принимает InnerException
, а также дополнительную информацию, и бросает ваш новый класс исключений, передавая ex
в качестве параметра InnerException
. Передавая исходный InnerException
, вы сохраняете все исходные свойства исключения, включая трассировку стека.
Первый сохраняет исходный стек:
try { ... }
catch
{
// Do something.
throw;
}
Второе позволяет вам изменить тип исключения и/или сообщение и другие данные:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
Также существует третий способ, по которому вы передаете внутреннее исключение:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
Я бы рекомендовал использовать:
throw
повторно выбрасывает исключение catch, сохраняя трассировку стека, а throw new Exception
теряет некоторые из деталей пойманного исключения.
Обычно вы обычно используете throw
для регистрации исключения без полной обработки его в этой точке.
BlackWasp имеет хорошую статью, достаточно озаглавленную Бросать исключения в С#.
Бросок нового Exception удаляет текущую трассировку стека.
throw;
сохранит исходную трассировку стека и почти всегда будет более полезной. Исключением из этого правила является то, что вы хотите обернуть исключение в собственное собственное Исключение. Затем вы должны:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
throw
предназначен для перехвата исключенного пойма. Это может быть полезно, если вы хотите сделать что-то с исключением, прежде чем передавать ему цепочку вызовов.
Использование throw
без каких-либо аргументов сохраняет стек вызовов для целей отладки.
Еще один момент, который я не видел никого:
Если вы ничего не делаете в своем блоке catch {}, попытка try... catch бессмысленна. Я все время вижу это:
try
{
//Code here
}
catch
{
throw;
}
Или хуже:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
Хуже всего:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
Если вы хотите, вы можете выбросить новое исключение, причем исходное значение будет установлено как внутреннее исключение.
В вашем втором примере будет reset трассировка стека исключений. Первый наиболее точно сохраняет происхождение исключения. Также вы развернули оригинальный тип, который является ключом к пониманию того, что на самом деле пошло не так... Если для функциональности требуется вторая функция - например, Чтобы добавить расширенную информацию или повторно обернуть специальным типом, например пользовательское "HandleableException", просто убедитесь, что свойство InnerException также установлено!
Самое важное отличие состоит в том, что второе выражение стирает тип исключения. И тип исключения играет жизненно важную роль в исключениях catching:
public void MyMethod ()
{
// both can throw IOException
try { foo(); } catch { throw; }
try { bar(); } catch(E) {throw new Exception(E.message); }
}
(...)
try {
MyMethod ();
} catch (IOException ex) {
Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
Console.WriteLine ("Other error"); // [2]
}
Если foo()
throws IOException
, блок блокировки [1]
поймает исключение. Но когда bar()
выбрасывает IOException
, он будет преобразован в обычный Exception
ant не будет пойман блоком catch [1]
.
throw или throw ex, оба используются для броска или повторного исключения исключения, когда вы просто регистрируете информацию об ошибках и не хотите отправлять какую-либо информацию обратно вызывающему, вы просто регистрируете ошибку в catch и leave. Но если вы хотите отправить какую-либо значимую информацию об исключении из вызывающего, который вы используете, бросьте или выбросьте ex. Теперь разница между throw и throw ex заключается в том, что бросок сохраняет трассировку стека и другую информацию, но throw ex создает новый объект исключения и, следовательно, потеряна исходная трассировка стека. Поэтому, когда мы должны использовать throw и throw e, Есть еще несколько ситуаций, в которых вы можете захотеть сбросить исключение, подобное reset информации стека вызовов. Например, если метод находится в библиотеке и вы хотите скрыть детали библиотеки от вызывающего кода, вам не обязательно, чтобы стек вызовов включал информацию о частных методах в библиотеке. В этом случае вы можете перехватывать исключения в общедоступных методах библиотеки, а затем восстанавливать их, чтобы стек вызовов начинался с этих общедоступных методов.