Хотя в нашем коде нет такой точной классификации, наша обработка исключений часто неявно указывает, считали ли мы возможным (экзогенным) конкретное исключение или мы просто учитываем возможные ошибки.
Используя пример Эрика, если мы получим доступ к файлу, поместим его в try/catch
и явно поймем FileNotFoundException
, то должно указать, что мы поняли, что FileNotFoundException
был возможным результатом, даже если мы проверили миллисекунду ранее, чтобы увидеть, существует ли она.
Если, с другой стороны, наш код включает это:
try
{
// do some stuff
}
catch(Exception ex)
{
// maybe log it
}
... это предполагает , что мы принимаем во внимание исключение с головой, что могло произойти где-нибудь в коде, выполняемом в try
.
Что (как бы) отличает их, так это то, что один указывает на то, что мы поняли, что это возможно, и объяснил это, а другой говорит: «Будем надеяться, что здесь все идет не так, как надо».
Даже это различие не совсем ясно. Наш код доступа к файлу может быть в «неопределенном» try/catch(Exception ex)
блоке. Мы знаем, что удаленно возможно, что из-за состояния гонки файл может не существовать. В этом случае мы просто позволим этой расплывчатой обработке исключений его поймать. Это может зависеть от того, что должно произойти. Если мы удаляли файл и оказалось, что он не существует, нам ничего не нужно делать. Если нам нужно было прочитать это, и теперь оно ушло, это всего лишь исключение. Возможно, нам не поможет поймать это конкретное исключение, если результат будет таким же, как и для любого другого исключения.
Точно так же, то, что мы явно отлавливаем исключение, не гарантирует, что оно не является "тупым". Может быть, я что-то не так делаю, и иногда мой код выдает ObjectDisposedException
. Я понятия не имею, почему это так, поэтому я добавляю catch(ObjectExposedException ex)
. На первый взгляд может показаться, что я знаю, что происходит в моем коде, но я действительно не знаю. Я должен был выяснить проблему и исправить ее вместо того, чтобы поймать исключение, не имея ни малейшего представления, почему это происходит. Если приложение не работает время от времени, и я не знаю почему, тот факт, что я поймал исключение, в лучшем случае бесполезен или в худшем случае вреден, поскольку скрывает то, что происходит на самом деле.
Это не значит, что мы должны добавлять операторы try/catch
в каждый метод, чтобы отлавливать "тупые" исключения. Это всего лишь пример обработки исключений, который учитывает возможность исключения, которое может быть или не быть ошибкой. Обычно это бесполезно делать в каждом методе. Мы могли бы поставить достаточно по краям, чтобы убедиться, что любое выброшенное исключение будет, по крайней мере, зарегистрировано.
Что касается перехвата и добавления исключений в новые исключения, то зачастую все сводится к тому, что вы планируете делать с той дополнительной информацией, которую вы создаете. Довольно часто ответом является ничего .
У нас может быть один слой приложения, который выбрасывает всевозможные хитроумные пользовательские исключения. Затем другой слой вызывает его и делает это:
try
{
_otherLayer.DoSomeStuff();
}
catch(Exception ex)
{
_logger.Log(ex);
}
Что мы сделали с нашим необычным пользовательским исключением? Мы только что зарегистрировали это, так же, как если бы мы не завернули его. Когда мы смотрим на наши журналы, мы игнорируем пользовательское исключение и просто просматриваем трассировку стека исходного исключения. Он сообщает нам, из какой сборки, класса и метода произошло исключение. Это, вероятно, все, что нам нужно.
Если цель заключенного в исключение исключения состоит в добавлении контекста, например
throw new DataStoreLoadException($"Unable to get the customer with id {id} from SQL database.", ex);
... это может быть полезно. Если бы мы этого не делали, то исключением было бы «Последовательность не содержит элементов». Это не так ясно.
Но возможно ли, что мы получим точно такой же пробег от этого?
throw new Exception($"Unable to get the customer with id {id} from SQL database.", ex);
Если нигде нет строки кода, в которой говорится, что catch(DataStoreLoadException ex)
и делают что-то иное, чем это было бы с любым другим исключением , то, скорее всего, мы от этого не получим никакой выгоды.
Стоит отметить, что несколько лет назад Microsoft рекомендовала наследовать наши пользовательские исключения от ApplicationException
вместо Exception
.Это будет отличать пользовательские и системные исключения.Но стало очевидно, что это различие не добавило ценности.Мы не говорили: «Если это ApplicationException
, сделайте это, иначе сделайте это».То же самое часто верно и для других пользовательских исключений, которые мы определяем.